mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 23:21:29 +00:00 
			
		
		
		
	Initial revision
This commit is contained in:
		
							parent
							
								
									33a6da9971
								
							
						
					
					
						commit
						7aced17437
					
				
					 73 changed files with 12383 additions and 0 deletions
				
			
		
							
								
								
									
										92
									
								
								Lib/idlelib/AutoExpand.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								Lib/idlelib/AutoExpand.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,92 @@
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###$ event <<expand-word>>
 | 
				
			||||||
 | 
					###$ win <Alt-slash>
 | 
				
			||||||
 | 
					###$ unix <Alt-slash>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AutoExpand:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    keydefs = {
 | 
				
			||||||
 | 
					        '<<expand-word>>': ['<Alt-slash>'],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unix_keydefs = {
 | 
				
			||||||
 | 
					        '<<expand-word>>': ['<Meta-slash>'],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    menudefs = [
 | 
				
			||||||
 | 
					        ('edit', [
 | 
				
			||||||
 | 
					            ('E_xpand word', '<<expand-word>>'),
 | 
				
			||||||
 | 
					         ]),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    wordchars = string.letters + string.digits + "_"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, editwin):
 | 
				
			||||||
 | 
					        self.text = editwin.text
 | 
				
			||||||
 | 
					        self.text.wordlist = None # XXX what is this?
 | 
				
			||||||
 | 
					        self.state = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def expand_word_event(self, event):
 | 
				
			||||||
 | 
					        curinsert = self.text.index("insert")
 | 
				
			||||||
 | 
					        curline = self.text.get("insert linestart", "insert lineend")
 | 
				
			||||||
 | 
					        if not self.state:
 | 
				
			||||||
 | 
					            words = self.getwords()
 | 
				
			||||||
 | 
					            index = 0
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            words, index, insert, line = self.state
 | 
				
			||||||
 | 
					            if insert != curinsert or line != curline:
 | 
				
			||||||
 | 
					                words = self.getwords()
 | 
				
			||||||
 | 
					                index = 0
 | 
				
			||||||
 | 
					        if not words:
 | 
				
			||||||
 | 
					            self.text.bell()
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					        word = self.getprevword()
 | 
				
			||||||
 | 
					        self.text.delete("insert - %d chars" % len(word), "insert")
 | 
				
			||||||
 | 
					        newword = words[index]
 | 
				
			||||||
 | 
					        index = (index + 1) % len(words)
 | 
				
			||||||
 | 
					        if index == 0:
 | 
				
			||||||
 | 
					            self.text.bell()            # Warn we cycled around
 | 
				
			||||||
 | 
					        self.text.insert("insert", newword)
 | 
				
			||||||
 | 
					        curinsert = self.text.index("insert")
 | 
				
			||||||
 | 
					        curline = self.text.get("insert linestart", "insert lineend")
 | 
				
			||||||
 | 
					        self.state = words, index, curinsert, curline
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getwords(self):
 | 
				
			||||||
 | 
					        word = self.getprevword()
 | 
				
			||||||
 | 
					        if not word:
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					        before = self.text.get("1.0", "insert wordstart")
 | 
				
			||||||
 | 
					        wbefore = re.findall(r"\b" + word + r"\w+\b", before)
 | 
				
			||||||
 | 
					        del before
 | 
				
			||||||
 | 
					        after = self.text.get("insert wordend", "end")
 | 
				
			||||||
 | 
					        wafter = re.findall(r"\b" + word + r"\w+\b", after)
 | 
				
			||||||
 | 
					        del after
 | 
				
			||||||
 | 
					        if not wbefore and not wafter:
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					        words = []
 | 
				
			||||||
 | 
					        dict = {}
 | 
				
			||||||
 | 
					        # search backwards through words before
 | 
				
			||||||
 | 
					        wbefore.reverse()
 | 
				
			||||||
 | 
					        for w in wbefore:
 | 
				
			||||||
 | 
					            if dict.get(w):
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            words.append(w)
 | 
				
			||||||
 | 
					            dict[w] = w
 | 
				
			||||||
 | 
					        # search onwards through words after
 | 
				
			||||||
 | 
					        for w in wafter:
 | 
				
			||||||
 | 
					            if dict.get(w):
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            words.append(w)
 | 
				
			||||||
 | 
					            dict[w] = w
 | 
				
			||||||
 | 
					        words.append(word)
 | 
				
			||||||
 | 
					        return words
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getprevword(self):
 | 
				
			||||||
 | 
					        line = self.text.get("insert linestart", "insert")
 | 
				
			||||||
 | 
					        i = len(line)
 | 
				
			||||||
 | 
					        while i > 0 and line[i-1] in self.wordchars:
 | 
				
			||||||
 | 
					            i = i-1
 | 
				
			||||||
 | 
					        return line[i:]
 | 
				
			||||||
							
								
								
									
										554
									
								
								Lib/idlelib/AutoIndent.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										554
									
								
								Lib/idlelib/AutoIndent.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,554 @@
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					#from Tkinter import TclError
 | 
				
			||||||
 | 
					#import tkMessageBox
 | 
				
			||||||
 | 
					#import tkSimpleDialog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###$ event <<newline-and-indent>>
 | 
				
			||||||
 | 
					###$ win <Key-Return>
 | 
				
			||||||
 | 
					###$ win <KP_Enter>
 | 
				
			||||||
 | 
					###$ unix <Key-Return>
 | 
				
			||||||
 | 
					###$ unix <KP_Enter>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###$ event <<indent-region>>
 | 
				
			||||||
 | 
					###$ win <Control-bracketright>
 | 
				
			||||||
 | 
					###$ unix <Alt-bracketright>
 | 
				
			||||||
 | 
					###$ unix <Control-bracketright>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###$ event <<dedent-region>>
 | 
				
			||||||
 | 
					###$ win <Control-bracketleft>
 | 
				
			||||||
 | 
					###$ unix <Alt-bracketleft>
 | 
				
			||||||
 | 
					###$ unix <Control-bracketleft>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###$ event <<comment-region>>
 | 
				
			||||||
 | 
					###$ win <Alt-Key-3>
 | 
				
			||||||
 | 
					###$ unix <Alt-Key-3>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###$ event <<uncomment-region>>
 | 
				
			||||||
 | 
					###$ win <Alt-Key-4>
 | 
				
			||||||
 | 
					###$ unix <Alt-Key-4>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###$ event <<tabify-region>>
 | 
				
			||||||
 | 
					###$ win <Alt-Key-5>
 | 
				
			||||||
 | 
					###$ unix <Alt-Key-5>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###$ event <<untabify-region>>
 | 
				
			||||||
 | 
					###$ win <Alt-Key-6>
 | 
				
			||||||
 | 
					###$ unix <Alt-Key-6>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import PyParse
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AutoIndent:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    menudefs = [
 | 
				
			||||||
 | 
					        ('format', [       # /s/edit/format   dscherer@cmu.edu
 | 
				
			||||||
 | 
					            None,
 | 
				
			||||||
 | 
					            ('_Indent region', '<<indent-region>>'),
 | 
				
			||||||
 | 
					            ('_Dedent region', '<<dedent-region>>'),
 | 
				
			||||||
 | 
					            ('Comment _out region', '<<comment-region>>'),
 | 
				
			||||||
 | 
					            ('U_ncomment region', '<<uncomment-region>>'),
 | 
				
			||||||
 | 
					            ('Tabify region', '<<tabify-region>>'),
 | 
				
			||||||
 | 
					            ('Untabify region', '<<untabify-region>>'),
 | 
				
			||||||
 | 
					            ('Toggle tabs', '<<toggle-tabs>>'),
 | 
				
			||||||
 | 
					            ('New indent width', '<<change-indentwidth>>'),
 | 
				
			||||||
 | 
					        ]),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    keydefs = {
 | 
				
			||||||
 | 
					        '<<smart-backspace>>': ['<Key-BackSpace>'],
 | 
				
			||||||
 | 
					        '<<newline-and-indent>>': ['<Key-Return>', '<KP_Enter>'],
 | 
				
			||||||
 | 
					        '<<smart-indent>>': ['<Key-Tab>']
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    windows_keydefs = {
 | 
				
			||||||
 | 
					        '<<indent-region>>': ['<Control-bracketright>'],
 | 
				
			||||||
 | 
					        '<<dedent-region>>': ['<Shift-Tab>',     # dscherer@cmu.edu
 | 
				
			||||||
 | 
					                              '<Control-bracketleft>'],
 | 
				
			||||||
 | 
					        '<<comment-region>>': ['<Alt-Key-3>'],
 | 
				
			||||||
 | 
					        '<<uncomment-region>>': ['<Alt-Key-4>'],
 | 
				
			||||||
 | 
					        '<<tabify-region>>': ['<Alt-Key-5>'],
 | 
				
			||||||
 | 
					        '<<untabify-region>>': ['<Alt-Key-6>'],
 | 
				
			||||||
 | 
					        '<<toggle-tabs>>': ['<Alt-Key-t>'],
 | 
				
			||||||
 | 
					        '<<change-indentwidth>>': ['<Alt-Key-u>'],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unix_keydefs = {
 | 
				
			||||||
 | 
					        '<<indent-region>>': ['<Alt-bracketright>',
 | 
				
			||||||
 | 
					                              '<Meta-bracketright>',
 | 
				
			||||||
 | 
					                              '<Control-bracketright>'],
 | 
				
			||||||
 | 
					        '<<dedent-region>>': ['<Alt-bracketleft>',
 | 
				
			||||||
 | 
					                              '<Meta-bracketleft>',
 | 
				
			||||||
 | 
					                              '<Control-bracketleft>'],
 | 
				
			||||||
 | 
					        '<<comment-region>>': ['<Alt-Key-3>', '<Meta-Key-3>'],
 | 
				
			||||||
 | 
					        '<<uncomment-region>>': ['<Alt-Key-4>', '<Meta-Key-4>'],
 | 
				
			||||||
 | 
					        '<<tabify-region>>': ['<Alt-Key-5>', '<Meta-Key-5>'],
 | 
				
			||||||
 | 
					        '<<untabify-region>>': ['<Alt-Key-6>', '<Meta-Key-6>'],
 | 
				
			||||||
 | 
					        '<<toggle-tabs>>': ['<Alt-Key-t>'],
 | 
				
			||||||
 | 
					        '<<change-indentwidth>>': ['<Alt-Key-u>'],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # usetabs true  -> literal tab characters are used by indent and
 | 
				
			||||||
 | 
					    #                  dedent cmds, possibly mixed with spaces if
 | 
				
			||||||
 | 
					    #                  indentwidth is not a multiple of tabwidth
 | 
				
			||||||
 | 
					    #         false -> tab characters are converted to spaces by indent
 | 
				
			||||||
 | 
					    #                  and dedent cmds, and ditto TAB keystrokes
 | 
				
			||||||
 | 
					    # indentwidth is the number of characters per logical indent level.
 | 
				
			||||||
 | 
					    # tabwidth is the display width of a literal tab character.
 | 
				
			||||||
 | 
					    # CAUTION:  telling Tk to use anything other than its default
 | 
				
			||||||
 | 
					    # tab setting causes it to use an entirely different tabbing algorithm,
 | 
				
			||||||
 | 
					    # treating tab stops as fixed distances from the left margin.
 | 
				
			||||||
 | 
					    # Nobody expects this, so for now tabwidth should never be changed.
 | 
				
			||||||
 | 
					    usetabs = 1
 | 
				
			||||||
 | 
					    indentwidth = 4
 | 
				
			||||||
 | 
					    tabwidth = 8    # for IDLE use, must remain 8 until Tk is fixed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # If context_use_ps1 is true, parsing searches back for a ps1 line;
 | 
				
			||||||
 | 
					    # else searches for a popular (if, def, ...) Python stmt.
 | 
				
			||||||
 | 
					    context_use_ps1 = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # When searching backwards for a reliable place to begin parsing,
 | 
				
			||||||
 | 
					    # first start num_context_lines[0] lines back, then
 | 
				
			||||||
 | 
					    # num_context_lines[1] lines back if that didn't work, and so on.
 | 
				
			||||||
 | 
					    # The last value should be huge (larger than the # of lines in a
 | 
				
			||||||
 | 
					    # conceivable file).
 | 
				
			||||||
 | 
					    # Making the initial values larger slows things down more often.
 | 
				
			||||||
 | 
					    num_context_lines = 50, 500, 5000000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, editwin):
 | 
				
			||||||
 | 
					        self.editwin = editwin
 | 
				
			||||||
 | 
					        self.text = editwin.text
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def config(self, **options):
 | 
				
			||||||
 | 
					        for key, value in options.items():
 | 
				
			||||||
 | 
					            if key == 'usetabs':
 | 
				
			||||||
 | 
					                self.usetabs = value
 | 
				
			||||||
 | 
					            elif key == 'indentwidth':
 | 
				
			||||||
 | 
					                self.indentwidth = value
 | 
				
			||||||
 | 
					            elif key == 'tabwidth':
 | 
				
			||||||
 | 
					                self.tabwidth = value
 | 
				
			||||||
 | 
					            elif key == 'context_use_ps1':
 | 
				
			||||||
 | 
					                self.context_use_ps1 = value
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                raise KeyError, "bad option name: %s" % `key`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # If ispythonsource and guess are true, guess a good value for
 | 
				
			||||||
 | 
					    # indentwidth based on file content (if possible), and if
 | 
				
			||||||
 | 
					    # indentwidth != tabwidth set usetabs false.
 | 
				
			||||||
 | 
					    # In any case, adjust the Text widget's view of what a tab
 | 
				
			||||||
 | 
					    # character means.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_indentation_params(self, ispythonsource, guess=1):
 | 
				
			||||||
 | 
					        if guess and ispythonsource:
 | 
				
			||||||
 | 
					            i = self.guess_indent()
 | 
				
			||||||
 | 
					            if 2 <= i <= 8:
 | 
				
			||||||
 | 
					                self.indentwidth = i
 | 
				
			||||||
 | 
					            if self.indentwidth != self.tabwidth:
 | 
				
			||||||
 | 
					                self.usetabs = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.editwin.set_tabwidth(self.tabwidth)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def smart_backspace_event(self, event):
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        first, last = self.editwin.get_selection_indices()
 | 
				
			||||||
 | 
					        if first and last:
 | 
				
			||||||
 | 
					            text.delete(first, last)
 | 
				
			||||||
 | 
					            text.mark_set("insert", first)
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					        # Delete whitespace left, until hitting a real char or closest
 | 
				
			||||||
 | 
					        # preceding virtual tab stop.
 | 
				
			||||||
 | 
					        chars = text.get("insert linestart", "insert")
 | 
				
			||||||
 | 
					        if chars == '':
 | 
				
			||||||
 | 
					            if text.compare("insert", ">", "1.0"):
 | 
				
			||||||
 | 
					                # easy: delete preceding newline
 | 
				
			||||||
 | 
					                text.delete("insert-1c")
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                text.bell()     # at start of buffer
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					        if  chars[-1] not in " \t":
 | 
				
			||||||
 | 
					            # easy: delete preceding real char
 | 
				
			||||||
 | 
					            text.delete("insert-1c")
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					        # Ick.  It may require *inserting* spaces if we back up over a
 | 
				
			||||||
 | 
					        # tab character!  This is written to be clear, not fast.
 | 
				
			||||||
 | 
					        expand, tabwidth = string.expandtabs, self.tabwidth
 | 
				
			||||||
 | 
					        have = len(expand(chars, tabwidth))
 | 
				
			||||||
 | 
					        assert have > 0
 | 
				
			||||||
 | 
					        want = int((have - 1) / self.indentwidth) * self.indentwidth
 | 
				
			||||||
 | 
					        ncharsdeleted = 0
 | 
				
			||||||
 | 
					        while 1:
 | 
				
			||||||
 | 
					            chars = chars[:-1]
 | 
				
			||||||
 | 
					            ncharsdeleted = ncharsdeleted + 1
 | 
				
			||||||
 | 
					            have = len(expand(chars, tabwidth))
 | 
				
			||||||
 | 
					            if have <= want or chars[-1] not in " \t":
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					        text.undo_block_start()
 | 
				
			||||||
 | 
					        text.delete("insert-%dc" % ncharsdeleted, "insert")
 | 
				
			||||||
 | 
					        if have < want:
 | 
				
			||||||
 | 
					            text.insert("insert", ' ' * (want - have))
 | 
				
			||||||
 | 
					        text.undo_block_stop()
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def smart_indent_event(self, event):
 | 
				
			||||||
 | 
					        # if intraline selection:
 | 
				
			||||||
 | 
					        #     delete it
 | 
				
			||||||
 | 
					        # elif multiline selection:
 | 
				
			||||||
 | 
					        #     do indent-region & return
 | 
				
			||||||
 | 
					        # indent one level
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        first, last = self.editwin.get_selection_indices()
 | 
				
			||||||
 | 
					        text.undo_block_start()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            if first and last:
 | 
				
			||||||
 | 
					                if index2line(first) != index2line(last):
 | 
				
			||||||
 | 
					                    return self.indent_region_event(event)
 | 
				
			||||||
 | 
					                text.delete(first, last)
 | 
				
			||||||
 | 
					                text.mark_set("insert", first)
 | 
				
			||||||
 | 
					            prefix = text.get("insert linestart", "insert")
 | 
				
			||||||
 | 
					            raw, effective = classifyws(prefix, self.tabwidth)
 | 
				
			||||||
 | 
					            if raw == len(prefix):
 | 
				
			||||||
 | 
					                # only whitespace to the left
 | 
				
			||||||
 | 
					                self.reindent_to(effective + self.indentwidth)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                if self.usetabs:
 | 
				
			||||||
 | 
					                    pad = '\t'
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    effective = len(string.expandtabs(prefix,
 | 
				
			||||||
 | 
					                                                      self.tabwidth))
 | 
				
			||||||
 | 
					                    n = self.indentwidth
 | 
				
			||||||
 | 
					                    pad = ' ' * (n - effective % n)
 | 
				
			||||||
 | 
					                text.insert("insert", pad)
 | 
				
			||||||
 | 
					            text.see("insert")
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            text.undo_block_stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def newline_and_indent_event(self, event):
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        first, last = self.editwin.get_selection_indices()
 | 
				
			||||||
 | 
					        text.undo_block_start()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            if first and last:
 | 
				
			||||||
 | 
					                text.delete(first, last)
 | 
				
			||||||
 | 
					                text.mark_set("insert", first)
 | 
				
			||||||
 | 
					            line = text.get("insert linestart", "insert")
 | 
				
			||||||
 | 
					            i, n = 0, len(line)
 | 
				
			||||||
 | 
					            while i < n and line[i] in " \t":
 | 
				
			||||||
 | 
					                i = i+1
 | 
				
			||||||
 | 
					            if i == n:
 | 
				
			||||||
 | 
					                # the cursor is in or at leading indentation; just inject
 | 
				
			||||||
 | 
					                # an empty line at the start
 | 
				
			||||||
 | 
					                text.insert("insert linestart", '\n')
 | 
				
			||||||
 | 
					                return "break"
 | 
				
			||||||
 | 
					            indent = line[:i]
 | 
				
			||||||
 | 
					            # strip whitespace before insert point
 | 
				
			||||||
 | 
					            i = 0
 | 
				
			||||||
 | 
					            while line and line[-1] in " \t":
 | 
				
			||||||
 | 
					                line = line[:-1]
 | 
				
			||||||
 | 
					                i = i+1
 | 
				
			||||||
 | 
					            if i:
 | 
				
			||||||
 | 
					                text.delete("insert - %d chars" % i, "insert")
 | 
				
			||||||
 | 
					            # strip whitespace after insert point
 | 
				
			||||||
 | 
					            while text.get("insert") in " \t":
 | 
				
			||||||
 | 
					                text.delete("insert")
 | 
				
			||||||
 | 
					            # start new line
 | 
				
			||||||
 | 
					            text.insert("insert", '\n')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # adjust indentation for continuations and block
 | 
				
			||||||
 | 
					            # open/close first need to find the last stmt
 | 
				
			||||||
 | 
					            lno = index2line(text.index('insert'))
 | 
				
			||||||
 | 
					            y = PyParse.Parser(self.indentwidth, self.tabwidth)
 | 
				
			||||||
 | 
					            for context in self.num_context_lines:
 | 
				
			||||||
 | 
					                startat = max(lno - context, 1)
 | 
				
			||||||
 | 
					                startatindex = `startat` + ".0"
 | 
				
			||||||
 | 
					                rawtext = text.get(startatindex, "insert")
 | 
				
			||||||
 | 
					                y.set_str(rawtext)
 | 
				
			||||||
 | 
					                bod = y.find_good_parse_start(
 | 
				
			||||||
 | 
					                          self.context_use_ps1,
 | 
				
			||||||
 | 
					                          self._build_char_in_string_func(startatindex))
 | 
				
			||||||
 | 
					                if bod is not None or startat == 1:
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					            y.set_lo(bod or 0)
 | 
				
			||||||
 | 
					            c = y.get_continuation_type()
 | 
				
			||||||
 | 
					            if c != PyParse.C_NONE:
 | 
				
			||||||
 | 
					                # The current stmt hasn't ended yet.
 | 
				
			||||||
 | 
					                if c == PyParse.C_STRING:
 | 
				
			||||||
 | 
					                    # inside a string; just mimic the current indent
 | 
				
			||||||
 | 
					                    text.insert("insert", indent)
 | 
				
			||||||
 | 
					                elif c == PyParse.C_BRACKET:
 | 
				
			||||||
 | 
					                    # line up with the first (if any) element of the
 | 
				
			||||||
 | 
					                    # last open bracket structure; else indent one
 | 
				
			||||||
 | 
					                    # level beyond the indent of the line with the
 | 
				
			||||||
 | 
					                    # last open bracket
 | 
				
			||||||
 | 
					                    self.reindent_to(y.compute_bracket_indent())
 | 
				
			||||||
 | 
					                elif c == PyParse.C_BACKSLASH:
 | 
				
			||||||
 | 
					                    # if more than one line in this stmt already, just
 | 
				
			||||||
 | 
					                    # mimic the current indent; else if initial line
 | 
				
			||||||
 | 
					                    # has a start on an assignment stmt, indent to
 | 
				
			||||||
 | 
					                    # beyond leftmost =; else to beyond first chunk of
 | 
				
			||||||
 | 
					                    # non-whitespace on initial line
 | 
				
			||||||
 | 
					                    if y.get_num_lines_in_stmt() > 1:
 | 
				
			||||||
 | 
					                        text.insert("insert", indent)
 | 
				
			||||||
 | 
					                    else:
 | 
				
			||||||
 | 
					                        self.reindent_to(y.compute_backslash_indent())
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    assert 0, "bogus continuation type " + `c`
 | 
				
			||||||
 | 
					                return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # This line starts a brand new stmt; indent relative to
 | 
				
			||||||
 | 
					            # indentation of initial line of closest preceding
 | 
				
			||||||
 | 
					            # interesting stmt.
 | 
				
			||||||
 | 
					            indent = y.get_base_indent_string()
 | 
				
			||||||
 | 
					            text.insert("insert", indent)
 | 
				
			||||||
 | 
					            if y.is_block_opener():
 | 
				
			||||||
 | 
					                self.smart_indent_event(event)
 | 
				
			||||||
 | 
					            elif indent and y.is_block_closer():
 | 
				
			||||||
 | 
					                self.smart_backspace_event(event)
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            text.see("insert")
 | 
				
			||||||
 | 
					            text.undo_block_stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    auto_indent = newline_and_indent_event
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Our editwin provides a is_char_in_string function that works
 | 
				
			||||||
 | 
					    # with a Tk text index, but PyParse only knows about offsets into
 | 
				
			||||||
 | 
					    # a string. This builds a function for PyParse that accepts an
 | 
				
			||||||
 | 
					    # offset.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _build_char_in_string_func(self, startindex):
 | 
				
			||||||
 | 
					        def inner(offset, _startindex=startindex,
 | 
				
			||||||
 | 
					                  _icis=self.editwin.is_char_in_string):
 | 
				
			||||||
 | 
					            return _icis(_startindex + "+%dc" % offset)
 | 
				
			||||||
 | 
					        return inner
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def indent_region_event(self, event):
 | 
				
			||||||
 | 
					        head, tail, chars, lines = self.get_region()
 | 
				
			||||||
 | 
					        for pos in range(len(lines)):
 | 
				
			||||||
 | 
					            line = lines[pos]
 | 
				
			||||||
 | 
					            if line:
 | 
				
			||||||
 | 
					                raw, effective = classifyws(line, self.tabwidth)
 | 
				
			||||||
 | 
					                effective = effective + self.indentwidth
 | 
				
			||||||
 | 
					                lines[pos] = self._make_blanks(effective) + line[raw:]
 | 
				
			||||||
 | 
					        self.set_region(head, tail, chars, lines)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dedent_region_event(self, event):
 | 
				
			||||||
 | 
					        head, tail, chars, lines = self.get_region()
 | 
				
			||||||
 | 
					        for pos in range(len(lines)):
 | 
				
			||||||
 | 
					            line = lines[pos]
 | 
				
			||||||
 | 
					            if line:
 | 
				
			||||||
 | 
					                raw, effective = classifyws(line, self.tabwidth)
 | 
				
			||||||
 | 
					                effective = max(effective - self.indentwidth, 0)
 | 
				
			||||||
 | 
					                lines[pos] = self._make_blanks(effective) + line[raw:]
 | 
				
			||||||
 | 
					        self.set_region(head, tail, chars, lines)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def comment_region_event(self, event):
 | 
				
			||||||
 | 
					        head, tail, chars, lines = self.get_region()
 | 
				
			||||||
 | 
					        for pos in range(len(lines) - 1):
 | 
				
			||||||
 | 
					            line = lines[pos]
 | 
				
			||||||
 | 
					            lines[pos] = '##' + line
 | 
				
			||||||
 | 
					        self.set_region(head, tail, chars, lines)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def uncomment_region_event(self, event):
 | 
				
			||||||
 | 
					        head, tail, chars, lines = self.get_region()
 | 
				
			||||||
 | 
					        for pos in range(len(lines)):
 | 
				
			||||||
 | 
					            line = lines[pos]
 | 
				
			||||||
 | 
					            if not line:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            if line[:2] == '##':
 | 
				
			||||||
 | 
					                line = line[2:]
 | 
				
			||||||
 | 
					            elif line[:1] == '#':
 | 
				
			||||||
 | 
					                line = line[1:]
 | 
				
			||||||
 | 
					            lines[pos] = line
 | 
				
			||||||
 | 
					        self.set_region(head, tail, chars, lines)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def tabify_region_event(self, event):
 | 
				
			||||||
 | 
					        head, tail, chars, lines = self.get_region()
 | 
				
			||||||
 | 
					        tabwidth = self._asktabwidth()
 | 
				
			||||||
 | 
					        for pos in range(len(lines)):
 | 
				
			||||||
 | 
					            line = lines[pos]
 | 
				
			||||||
 | 
					            if line:
 | 
				
			||||||
 | 
					                raw, effective = classifyws(line, tabwidth)
 | 
				
			||||||
 | 
					                ntabs, nspaces = divmod(effective, tabwidth)
 | 
				
			||||||
 | 
					                lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:]
 | 
				
			||||||
 | 
					        self.set_region(head, tail, chars, lines)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def untabify_region_event(self, event):
 | 
				
			||||||
 | 
					        head, tail, chars, lines = self.get_region()
 | 
				
			||||||
 | 
					        tabwidth = self._asktabwidth()
 | 
				
			||||||
 | 
					        for pos in range(len(lines)):
 | 
				
			||||||
 | 
					            lines[pos] = string.expandtabs(lines[pos], tabwidth)
 | 
				
			||||||
 | 
					        self.set_region(head, tail, chars, lines)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def toggle_tabs_event(self, event):
 | 
				
			||||||
 | 
					        if self.editwin.askyesno(
 | 
				
			||||||
 | 
					              "Toggle tabs",
 | 
				
			||||||
 | 
					              "Turn tabs " + ("on", "off")[self.usetabs] + "?",
 | 
				
			||||||
 | 
					              parent=self.text):
 | 
				
			||||||
 | 
					            self.usetabs = not self.usetabs
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # XXX this isn't bound to anything -- see class tabwidth comments
 | 
				
			||||||
 | 
					    def change_tabwidth_event(self, event):
 | 
				
			||||||
 | 
					        new = self._asktabwidth()
 | 
				
			||||||
 | 
					        if new != self.tabwidth:
 | 
				
			||||||
 | 
					            self.tabwidth = new
 | 
				
			||||||
 | 
					            self.set_indentation_params(0, guess=0)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def change_indentwidth_event(self, event):
 | 
				
			||||||
 | 
					        new = self.editwin.askinteger(
 | 
				
			||||||
 | 
					                  "Indent width",
 | 
				
			||||||
 | 
					                  "New indent width (1-16)",
 | 
				
			||||||
 | 
					                  parent=self.text,
 | 
				
			||||||
 | 
					                  initialvalue=self.indentwidth,
 | 
				
			||||||
 | 
					                  minvalue=1,
 | 
				
			||||||
 | 
					                  maxvalue=16)
 | 
				
			||||||
 | 
					        if new and new != self.indentwidth:
 | 
				
			||||||
 | 
					            self.indentwidth = new
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_region(self):
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        first, last = self.editwin.get_selection_indices()
 | 
				
			||||||
 | 
					        if first and last:
 | 
				
			||||||
 | 
					            head = text.index(first + " linestart")
 | 
				
			||||||
 | 
					            tail = text.index(last + "-1c lineend +1c")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            head = text.index("insert linestart")
 | 
				
			||||||
 | 
					            tail = text.index("insert lineend +1c")
 | 
				
			||||||
 | 
					        chars = text.get(head, tail)
 | 
				
			||||||
 | 
					        lines = string.split(chars, "\n")
 | 
				
			||||||
 | 
					        return head, tail, chars, lines
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_region(self, head, tail, chars, lines):
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        newchars = string.join(lines, "\n")
 | 
				
			||||||
 | 
					        if newchars == chars:
 | 
				
			||||||
 | 
					            text.bell()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        text.tag_remove("sel", "1.0", "end")
 | 
				
			||||||
 | 
					        text.mark_set("insert", head)
 | 
				
			||||||
 | 
					        text.undo_block_start()
 | 
				
			||||||
 | 
					        text.delete(head, tail)
 | 
				
			||||||
 | 
					        text.insert(head, newchars)
 | 
				
			||||||
 | 
					        text.undo_block_stop()
 | 
				
			||||||
 | 
					        text.tag_add("sel", head, "insert")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Make string that displays as n leading blanks.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _make_blanks(self, n):
 | 
				
			||||||
 | 
					        if self.usetabs:
 | 
				
			||||||
 | 
					            ntabs, nspaces = divmod(n, self.tabwidth)
 | 
				
			||||||
 | 
					            return '\t' * ntabs + ' ' * nspaces
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return ' ' * n
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Delete from beginning of line to insert point, then reinsert
 | 
				
			||||||
 | 
					    # column logical (meaning use tabs if appropriate) spaces.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def reindent_to(self, column):
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        text.undo_block_start()
 | 
				
			||||||
 | 
					        if text.compare("insert linestart", "!=", "insert"):
 | 
				
			||||||
 | 
					            text.delete("insert linestart", "insert")
 | 
				
			||||||
 | 
					        if column:
 | 
				
			||||||
 | 
					            text.insert("insert", self._make_blanks(column))
 | 
				
			||||||
 | 
					        text.undo_block_stop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _asktabwidth(self):
 | 
				
			||||||
 | 
					        return self.editwin.askinteger(
 | 
				
			||||||
 | 
					            "Tab width",
 | 
				
			||||||
 | 
					            "Spaces per tab?",
 | 
				
			||||||
 | 
					            parent=self.text,
 | 
				
			||||||
 | 
					            initialvalue=self.tabwidth,
 | 
				
			||||||
 | 
					            minvalue=1,
 | 
				
			||||||
 | 
					            maxvalue=16) or self.tabwidth
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Guess indentwidth from text content.
 | 
				
			||||||
 | 
					    # Return guessed indentwidth.  This should not be believed unless
 | 
				
			||||||
 | 
					    # it's in a reasonable range (e.g., it will be 0 if no indented
 | 
				
			||||||
 | 
					    # blocks are found).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def guess_indent(self):
 | 
				
			||||||
 | 
					        opener, indented = IndentSearcher(self.text, self.tabwidth).run()
 | 
				
			||||||
 | 
					        if opener and indented:
 | 
				
			||||||
 | 
					            raw, indentsmall = classifyws(opener, self.tabwidth)
 | 
				
			||||||
 | 
					            raw, indentlarge = classifyws(indented, self.tabwidth)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            indentsmall = indentlarge = 0
 | 
				
			||||||
 | 
					        return indentlarge - indentsmall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# "line.col" -> line, as an int
 | 
				
			||||||
 | 
					def index2line(index):
 | 
				
			||||||
 | 
					    return int(float(index))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Look at the leading whitespace in s.
 | 
				
			||||||
 | 
					# Return pair (# of leading ws characters,
 | 
				
			||||||
 | 
					#              effective # of leading blanks after expanding
 | 
				
			||||||
 | 
					#              tabs to width tabwidth)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def classifyws(s, tabwidth):
 | 
				
			||||||
 | 
					    raw = effective = 0
 | 
				
			||||||
 | 
					    for ch in s:
 | 
				
			||||||
 | 
					        if ch == ' ':
 | 
				
			||||||
 | 
					            raw = raw + 1
 | 
				
			||||||
 | 
					            effective = effective + 1
 | 
				
			||||||
 | 
					        elif ch == '\t':
 | 
				
			||||||
 | 
					            raw = raw + 1
 | 
				
			||||||
 | 
					            effective = (effective / tabwidth + 1) * tabwidth
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            break
 | 
				
			||||||
 | 
					    return raw, effective
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import tokenize
 | 
				
			||||||
 | 
					_tokenize = tokenize
 | 
				
			||||||
 | 
					del tokenize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IndentSearcher:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # .run() chews over the Text widget, looking for a block opener
 | 
				
			||||||
 | 
					    # and the stmt following it.  Returns a pair,
 | 
				
			||||||
 | 
					    #     (line containing block opener, line containing stmt)
 | 
				
			||||||
 | 
					    # Either or both may be None.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, text, tabwidth):
 | 
				
			||||||
 | 
					        self.text = text
 | 
				
			||||||
 | 
					        self.tabwidth = tabwidth
 | 
				
			||||||
 | 
					        self.i = self.finished = 0
 | 
				
			||||||
 | 
					        self.blkopenline = self.indentedline = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def readline(self):
 | 
				
			||||||
 | 
					        if self.finished:
 | 
				
			||||||
 | 
					            return ""
 | 
				
			||||||
 | 
					        i = self.i = self.i + 1
 | 
				
			||||||
 | 
					        mark = `i` + ".0"
 | 
				
			||||||
 | 
					        if self.text.compare(mark, ">=", "end"):
 | 
				
			||||||
 | 
					            return ""
 | 
				
			||||||
 | 
					        return self.text.get(mark, mark + " lineend+1c")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def tokeneater(self, type, token, start, end, line,
 | 
				
			||||||
 | 
					                   INDENT=_tokenize.INDENT,
 | 
				
			||||||
 | 
					                   NAME=_tokenize.NAME,
 | 
				
			||||||
 | 
					                   OPENERS=('class', 'def', 'for', 'if', 'try', 'while')):
 | 
				
			||||||
 | 
					        if self.finished:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        elif type == NAME and token in OPENERS:
 | 
				
			||||||
 | 
					            self.blkopenline = line
 | 
				
			||||||
 | 
					        elif type == INDENT and self.blkopenline:
 | 
				
			||||||
 | 
					            self.indentedline = line
 | 
				
			||||||
 | 
					            self.finished = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run(self):
 | 
				
			||||||
 | 
					        save_tabsize = _tokenize.tabsize
 | 
				
			||||||
 | 
					        _tokenize.tabsize = self.tabwidth
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                _tokenize.tokenize(self.readline, self.tokeneater)
 | 
				
			||||||
 | 
					            except _tokenize.TokenError:
 | 
				
			||||||
 | 
					                # since we cut off the tokenizer early, we can trigger
 | 
				
			||||||
 | 
					                # spurious errors
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            _tokenize.tabsize = save_tabsize
 | 
				
			||||||
 | 
					        return self.blkopenline, self.indentedline
 | 
				
			||||||
							
								
								
									
										67
									
								
								Lib/idlelib/Bindings.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								Lib/idlelib/Bindings.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,67 @@
 | 
				
			||||||
 | 
					# This file defines the menu contents and key bindings.  Note that
 | 
				
			||||||
 | 
					# there is additional configuration information in the EditorWindow
 | 
				
			||||||
 | 
					# class (and subclasses): the menus are created there based on the
 | 
				
			||||||
 | 
					# menu_specs (class) variable, and menus not created are silently
 | 
				
			||||||
 | 
					# skipped by the code here.  This makes it possible to define the
 | 
				
			||||||
 | 
					# Debug menu here, which is only present in the PythonShell window.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# changes by dscherer@cmu.edu:
 | 
				
			||||||
 | 
					#   - Python shell moved to 'Run' menu
 | 
				
			||||||
 | 
					#   - "Help" renamed to "IDLE Help" to distinguish from Python help.
 | 
				
			||||||
 | 
					#     The distinction between the environment and the language is dim
 | 
				
			||||||
 | 
					#     or nonexistent in a novice's mind.
 | 
				
			||||||
 | 
					#   - Silly advice added
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					from keydefs import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					menudefs = [
 | 
				
			||||||
 | 
					 # underscore prefixes character to underscore
 | 
				
			||||||
 | 
					 ('file', [
 | 
				
			||||||
 | 
					   ('_New window', '<<open-new-window>>'),
 | 
				
			||||||
 | 
					   ('_Open...', '<<open-window-from-file>>'),
 | 
				
			||||||
 | 
					   ('Open _module...', '<<open-module>>'),
 | 
				
			||||||
 | 
					   ('Class _browser', '<<open-class-browser>>'),
 | 
				
			||||||
 | 
					   ('_Path browser', '<<open-path-browser>>'),
 | 
				
			||||||
 | 
					   None,
 | 
				
			||||||
 | 
					   ('_Save', '<<save-window>>'),
 | 
				
			||||||
 | 
					   ('Save _As...', '<<save-window-as-file>>'),
 | 
				
			||||||
 | 
					   ('Save Co_py As...', '<<save-copy-of-window-as-file>>'),
 | 
				
			||||||
 | 
					   None,
 | 
				
			||||||
 | 
					   ('_Close', '<<close-window>>'),
 | 
				
			||||||
 | 
					   ('E_xit', '<<close-all-windows>>'),
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					 ('edit', [
 | 
				
			||||||
 | 
					   ('_Undo', '<<undo>>'),
 | 
				
			||||||
 | 
					   ('_Redo', '<<redo>>'),
 | 
				
			||||||
 | 
					   None,
 | 
				
			||||||
 | 
					   ('Cu_t', '<<Cut>>'),
 | 
				
			||||||
 | 
					   ('_Copy', '<<Copy>>'),
 | 
				
			||||||
 | 
					   ('_Paste', '<<Paste>>'),
 | 
				
			||||||
 | 
					   ('Select _All', '<<select-all>>'),
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					 ('run',[
 | 
				
			||||||
 | 
					   ('Python shell', '<<open-python-shell>>'),
 | 
				
			||||||
 | 
					 ]),
 | 
				
			||||||
 | 
					 ('debug', [
 | 
				
			||||||
 | 
					   ('_Go to file/line', '<<goto-file-line>>'),
 | 
				
			||||||
 | 
					   ('_Stack viewer', '<<open-stack-viewer>>'),
 | 
				
			||||||
 | 
					   ('!_Debugger', '<<toggle-debugger>>'),
 | 
				
			||||||
 | 
					   ('!_Auto-open stack viewer', '<<toggle-jit-stack-viewer>>' ),
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					 ('help', [
 | 
				
			||||||
 | 
					   ('_IDLE Help...', '<<help>>'),
 | 
				
			||||||
 | 
					   ('Python _Documentation...', '<<python-docs>>'),
 | 
				
			||||||
 | 
					   ('_Advice...', '<<good-advice>>'),
 | 
				
			||||||
 | 
					   None,
 | 
				
			||||||
 | 
					   ('_About IDLE...', '<<about-idle>>'),
 | 
				
			||||||
 | 
					  ]),
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if sys.platform == 'win32':
 | 
				
			||||||
 | 
					    default_keydefs = windows_keydefs
 | 
				
			||||||
 | 
					else:
 | 
				
			||||||
 | 
					    default_keydefs = unix_keydefs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					del sys
 | 
				
			||||||
							
								
								
									
										71
									
								
								Lib/idlelib/CallTipWindow.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								Lib/idlelib/CallTipWindow.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,71 @@
 | 
				
			||||||
 | 
					# A CallTip window class for Tkinter/IDLE.
 | 
				
			||||||
 | 
					# After ToolTip.py, which uses ideas gleaned from PySol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Used by the CallTips IDLE extension.
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CallTip:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, widget):
 | 
				
			||||||
 | 
					        self.widget = widget
 | 
				
			||||||
 | 
					        self.tipwindow = None
 | 
				
			||||||
 | 
					        self.id = None
 | 
				
			||||||
 | 
					        self.x = self.y = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def showtip(self, text):
 | 
				
			||||||
 | 
					        self.text = text
 | 
				
			||||||
 | 
					        if self.tipwindow or not self.text:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.widget.see("insert")
 | 
				
			||||||
 | 
					        x, y, cx, cy = self.widget.bbox("insert")
 | 
				
			||||||
 | 
					        x = x + self.widget.winfo_rootx() + 2
 | 
				
			||||||
 | 
					        y = y + cy + self.widget.winfo_rooty()
 | 
				
			||||||
 | 
					        self.tipwindow = tw = Toplevel(self.widget)
 | 
				
			||||||
 | 
					        tw.wm_overrideredirect(1)
 | 
				
			||||||
 | 
					        tw.wm_geometry("+%d+%d" % (x, y))
 | 
				
			||||||
 | 
					        label = Label(tw, text=self.text, justify=LEFT,
 | 
				
			||||||
 | 
					                      background="#ffffe0", relief=SOLID, borderwidth=1,
 | 
				
			||||||
 | 
					                      font = self.widget['font'])
 | 
				
			||||||
 | 
					        label.pack()
 | 
				
			||||||
 | 
					                      
 | 
				
			||||||
 | 
					    def hidetip(self):
 | 
				
			||||||
 | 
					        tw = self.tipwindow
 | 
				
			||||||
 | 
					        self.tipwindow = None
 | 
				
			||||||
 | 
					        if tw:
 | 
				
			||||||
 | 
					            tw.destroy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###############################
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Test Code
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					class container: # Conceptually an editor_window
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        root = Tk()
 | 
				
			||||||
 | 
					        text = self.text = Text(root)
 | 
				
			||||||
 | 
					        text.pack(side=LEFT, fill=BOTH, expand=1)
 | 
				
			||||||
 | 
					        text.insert("insert", "string.split")
 | 
				
			||||||
 | 
					        root.update()
 | 
				
			||||||
 | 
					        self.calltip = CallTip(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        text.event_add("<<calltip-show>>", "(")
 | 
				
			||||||
 | 
					        text.event_add("<<calltip-hide>>", ")")
 | 
				
			||||||
 | 
					        text.bind("<<calltip-show>>", self.calltip_show)
 | 
				
			||||||
 | 
					        text.bind("<<calltip-hide>>", self.calltip_hide)
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        text.focus_set()
 | 
				
			||||||
 | 
					        # root.mainloop() # not in idle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def calltip_show(self, event):
 | 
				
			||||||
 | 
					        self.calltip.showtip("Hello world")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def calltip_hide(self, event):
 | 
				
			||||||
 | 
					        self.calltip.hidetip()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    # Test code
 | 
				
			||||||
 | 
					    c=container()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__=='__main__':
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										190
									
								
								Lib/idlelib/CallTips.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										190
									
								
								Lib/idlelib/CallTips.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,190 @@
 | 
				
			||||||
 | 
					# CallTips.py - An IDLE extension that provides "Call Tips" - ie, a floating window that
 | 
				
			||||||
 | 
					# displays parameter information as you open parens.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import types
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CallTips:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    menudefs = [
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    keydefs = {
 | 
				
			||||||
 | 
					        '<<paren-open>>': ['<Key-parenleft>'],
 | 
				
			||||||
 | 
					        '<<paren-close>>': ['<Key-parenright>'],
 | 
				
			||||||
 | 
					        '<<check-calltip-cancel>>': ['<KeyRelease>'],
 | 
				
			||||||
 | 
					        '<<calltip-cancel>>': ['<ButtonPress>', '<Key-Escape>'],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    windows_keydefs = {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unix_keydefs = {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, editwin):
 | 
				
			||||||
 | 
					        self.editwin = editwin
 | 
				
			||||||
 | 
					        self.text = editwin.text
 | 
				
			||||||
 | 
					        self.calltip = None
 | 
				
			||||||
 | 
					        if hasattr(self.text, "make_calltip_window"):
 | 
				
			||||||
 | 
					            self._make_calltip_window = self.text.make_calltip_window
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self._make_calltip_window = self._make_tk_calltip_window
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self):
 | 
				
			||||||
 | 
					        self._make_calltip_window = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Makes a Tk based calltip window.  Used by IDLE, but not Pythonwin.
 | 
				
			||||||
 | 
					    # See __init__ above for how this is used.
 | 
				
			||||||
 | 
					    def _make_tk_calltip_window(self):
 | 
				
			||||||
 | 
					        import CallTipWindow
 | 
				
			||||||
 | 
					        return CallTipWindow.CallTip(self.text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _remove_calltip_window(self):
 | 
				
			||||||
 | 
					        if self.calltip:
 | 
				
			||||||
 | 
					            self.calltip.hidetip()
 | 
				
			||||||
 | 
					            self.calltip = None
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    def paren_open_event(self, event):
 | 
				
			||||||
 | 
					        self._remove_calltip_window()
 | 
				
			||||||
 | 
					        arg_text = get_arg_text(self.get_object_at_cursor())
 | 
				
			||||||
 | 
					        if arg_text:
 | 
				
			||||||
 | 
					            self.calltip_start = self.text.index("insert")
 | 
				
			||||||
 | 
					            self.calltip = self._make_calltip_window()
 | 
				
			||||||
 | 
					            self.calltip.showtip(arg_text)
 | 
				
			||||||
 | 
					        return "" #so the event is handled normally.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def paren_close_event(self, event):
 | 
				
			||||||
 | 
					        # Now just hides, but later we should check if other
 | 
				
			||||||
 | 
					        # paren'd expressions remain open.
 | 
				
			||||||
 | 
					        self._remove_calltip_window()
 | 
				
			||||||
 | 
					        return "" #so the event is handled normally.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def check_calltip_cancel_event(self, event):
 | 
				
			||||||
 | 
					        if self.calltip:
 | 
				
			||||||
 | 
					            # If we have moved before the start of the calltip,
 | 
				
			||||||
 | 
					            # or off the calltip line, then cancel the tip.
 | 
				
			||||||
 | 
					            # (Later need to be smarter about multi-line, etc)
 | 
				
			||||||
 | 
					            if self.text.compare("insert", "<=", self.calltip_start) or \
 | 
				
			||||||
 | 
					               self.text.compare("insert", ">", self.calltip_start + " lineend"):
 | 
				
			||||||
 | 
					                self._remove_calltip_window()
 | 
				
			||||||
 | 
					        return "" #so the event is handled normally.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def calltip_cancel_event(self, event):
 | 
				
			||||||
 | 
					        self._remove_calltip_window()
 | 
				
			||||||
 | 
					        return "" #so the event is handled normally.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_object_at_cursor(self,
 | 
				
			||||||
 | 
					                             wordchars="._" + string.uppercase + string.lowercase + string.digits):
 | 
				
			||||||
 | 
					        # XXX - This needs to be moved to a better place
 | 
				
			||||||
 | 
					        # so the "." attribute lookup code can also use it.
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        chars = text.get("insert linestart", "insert")
 | 
				
			||||||
 | 
					        i = len(chars)
 | 
				
			||||||
 | 
					        while i and chars[i-1] in wordchars:
 | 
				
			||||||
 | 
					            i = i-1
 | 
				
			||||||
 | 
					        word = chars[i:]
 | 
				
			||||||
 | 
					        if word:
 | 
				
			||||||
 | 
					            # How is this for a hack!
 | 
				
			||||||
 | 
					            import sys, __main__
 | 
				
			||||||
 | 
					            namespace = sys.modules.copy()
 | 
				
			||||||
 | 
					            namespace.update(__main__.__dict__)
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                    return eval(word, namespace)
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                    pass
 | 
				
			||||||
 | 
					        return None # Can't find an object.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _find_constructor(class_ob):
 | 
				
			||||||
 | 
					    # Given a class object, return a function object used for the
 | 
				
			||||||
 | 
					    # constructor (ie, __init__() ) or None if we can't find one.
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        return class_ob.__init__.im_func
 | 
				
			||||||
 | 
					    except AttributeError:
 | 
				
			||||||
 | 
					        for base in class_ob.__bases__:
 | 
				
			||||||
 | 
					            rc = _find_constructor(base)
 | 
				
			||||||
 | 
					            if rc is not None: return rc
 | 
				
			||||||
 | 
					    return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_arg_text(ob):
 | 
				
			||||||
 | 
					    # Get a string describing the arguments for the given object.
 | 
				
			||||||
 | 
					    argText = ""
 | 
				
			||||||
 | 
					    if ob is not None:
 | 
				
			||||||
 | 
					        argOffset = 0
 | 
				
			||||||
 | 
					        if type(ob)==types.ClassType:
 | 
				
			||||||
 | 
					            # Look for the highest __init__ in the class chain.
 | 
				
			||||||
 | 
					            fob = _find_constructor(ob)
 | 
				
			||||||
 | 
					            if fob is None:
 | 
				
			||||||
 | 
					                fob = lambda: None
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                argOffset = 1
 | 
				
			||||||
 | 
					        elif type(ob)==types.MethodType:
 | 
				
			||||||
 | 
					            # bit of a hack for methods - turn it into a function
 | 
				
			||||||
 | 
					            # but we drop the "self" param.
 | 
				
			||||||
 | 
					            fob = ob.im_func
 | 
				
			||||||
 | 
					            argOffset = 1
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            fob = ob
 | 
				
			||||||
 | 
					        # Try and build one for Python defined functions
 | 
				
			||||||
 | 
					        if type(fob) in [types.FunctionType, types.LambdaType]:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                realArgs = fob.func_code.co_varnames[argOffset:fob.func_code.co_argcount]
 | 
				
			||||||
 | 
					                defaults = fob.func_defaults or []
 | 
				
			||||||
 | 
					                defaults = list(map(lambda name: "=%s" % name, defaults))
 | 
				
			||||||
 | 
					                defaults = [""] * (len(realArgs)-len(defaults)) + defaults
 | 
				
			||||||
 | 
					                items = map(lambda arg, dflt: arg+dflt, realArgs, defaults)
 | 
				
			||||||
 | 
					                if fob.func_code.co_flags & 0x4:
 | 
				
			||||||
 | 
					                    items.append("...")
 | 
				
			||||||
 | 
					                if fob.func_code.co_flags & 0x8:
 | 
				
			||||||
 | 
					                    items.append("***")
 | 
				
			||||||
 | 
					                argText = string.join(items , ", ")
 | 
				
			||||||
 | 
					                argText = "(%s)" % argText
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					        # See if we can use the docstring
 | 
				
			||||||
 | 
					        if hasattr(ob, "__doc__") and ob.__doc__:
 | 
				
			||||||
 | 
					            pos = string.find(ob.__doc__, "\n")
 | 
				
			||||||
 | 
					            if pos<0 or pos>70: pos=70
 | 
				
			||||||
 | 
					            if argText: argText = argText + "\n"
 | 
				
			||||||
 | 
					            argText = argText + ob.__doc__[:pos]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return argText
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#################################################
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Test code
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					if __name__=='__main__':
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def t1(): "()"
 | 
				
			||||||
 | 
					    def t2(a, b=None): "(a, b=None)"
 | 
				
			||||||
 | 
					    def t3(a, *args): "(a, ...)"
 | 
				
			||||||
 | 
					    def t4(*args): "(...)"
 | 
				
			||||||
 | 
					    def t5(a, *args): "(a, ...)"
 | 
				
			||||||
 | 
					    def t6(a, b=None, *args, **kw): "(a, b=None, ..., ***)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    class TC:
 | 
				
			||||||
 | 
					        "(a=None, ...)"
 | 
				
			||||||
 | 
					        def __init__(self, a=None, *b): "(a=None, ...)"
 | 
				
			||||||
 | 
					        def t1(self): "()"
 | 
				
			||||||
 | 
					        def t2(self, a, b=None): "(a, b=None)"
 | 
				
			||||||
 | 
					        def t3(self, a, *args): "(a, ...)"
 | 
				
			||||||
 | 
					        def t4(self, *args): "(...)"
 | 
				
			||||||
 | 
					        def t5(self, a, *args): "(a, ...)"
 | 
				
			||||||
 | 
					        def t6(self, a, b=None, *args, **kw): "(a, b=None, ..., ***)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def test( tests ):
 | 
				
			||||||
 | 
					        failed=[]
 | 
				
			||||||
 | 
					        for t in tests:
 | 
				
			||||||
 | 
					            expected = t.__doc__ + "\n" + t.__doc__
 | 
				
			||||||
 | 
					            if get_arg_text(t) != expected:
 | 
				
			||||||
 | 
					                failed.append(t)
 | 
				
			||||||
 | 
					                print "%s - expected %s, but got %s" % (t, `expected`, `get_arg_text(t)`)
 | 
				
			||||||
 | 
					        print "%d of %d tests failed" % (len(failed), len(tests))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tc = TC()
 | 
				
			||||||
 | 
					    tests = t1, t2, t3, t4, t5, t6, \
 | 
				
			||||||
 | 
					            TC, tc.t1, tc.t2, tc.t3, tc.t4, tc.t5, tc.t6
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    test(tests)
 | 
				
			||||||
							
								
								
									
										1017
									
								
								Lib/idlelib/ChangeLog
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1017
									
								
								Lib/idlelib/ChangeLog
									
										
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										224
									
								
								Lib/idlelib/ClassBrowser.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								Lib/idlelib/ClassBrowser.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,224 @@
 | 
				
			||||||
 | 
					"""Class browser.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					XXX TO DO:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- reparse when source changed (maybe just a button would be OK?)
 | 
				
			||||||
 | 
					    (or recheck on window popup)
 | 
				
			||||||
 | 
					- add popup menu with more options (e.g. doc strings, base classes, imports)
 | 
				
			||||||
 | 
					- show function argument list? (have to do pattern matching on source)
 | 
				
			||||||
 | 
					- should the classes and methods lists also be in the module's menu bar?
 | 
				
			||||||
 | 
					- add base classes to class browser tree
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import pyclbr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# XXX Patch pyclbr with dummies if it's vintage Python 1.5.2:
 | 
				
			||||||
 | 
					if not hasattr(pyclbr, "readmodule_ex"):
 | 
				
			||||||
 | 
					    pyclbr.readmodule_ex = pyclbr.readmodule
 | 
				
			||||||
 | 
					if not hasattr(pyclbr, "Function"):
 | 
				
			||||||
 | 
					    class Function(pyclbr.Class):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					    pyclbr.Function = Function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import PyShell
 | 
				
			||||||
 | 
					from WindowList import ListedToplevel
 | 
				
			||||||
 | 
					from TreeWidget import TreeNode, TreeItem, ScrolledCanvas
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ClassBrowser:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, flist, name, path):
 | 
				
			||||||
 | 
					        # XXX This API should change, if the file doesn't end in ".py"
 | 
				
			||||||
 | 
					        # XXX the code here is bogus!
 | 
				
			||||||
 | 
					        self.name = name
 | 
				
			||||||
 | 
					        self.file = os.path.join(path[0], self.name + ".py")
 | 
				
			||||||
 | 
					        self.init(flist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self, event=None):
 | 
				
			||||||
 | 
					        self.top.destroy()
 | 
				
			||||||
 | 
					        self.node.destroy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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)
 | 
				
			||||||
 | 
					        self.settitle()
 | 
				
			||||||
 | 
					        top.focus_set()
 | 
				
			||||||
 | 
					        # create scrolled canvas
 | 
				
			||||||
 | 
					        sc = ScrolledCanvas(top, bg="white", 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 settitle(self):
 | 
				
			||||||
 | 
					        self.top.wm_title("Class Browser - " + self.name)
 | 
				
			||||||
 | 
					        self.top.wm_iconname("Class Browser")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def rootnode(self):
 | 
				
			||||||
 | 
					        return ModuleBrowserTreeItem(self.file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ModuleBrowserTreeItem(TreeItem):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, file):
 | 
				
			||||||
 | 
					        self.file = file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetText(self):
 | 
				
			||||||
 | 
					        return os.path.basename(self.file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetIconName(self):
 | 
				
			||||||
 | 
					        return "python"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetSubList(self):
 | 
				
			||||||
 | 
					        sublist = []
 | 
				
			||||||
 | 
					        for name in self.listclasses():
 | 
				
			||||||
 | 
					            item = ClassBrowserTreeItem(name, self.classes, self.file)
 | 
				
			||||||
 | 
					            sublist.append(item)
 | 
				
			||||||
 | 
					        return sublist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def OnDoubleClick(self):
 | 
				
			||||||
 | 
					        if os.path.normcase(self.file[-3:]) != ".py":
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if not os.path.exists(self.file):
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        PyShell.flist.open(self.file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def IsExpandable(self):
 | 
				
			||||||
 | 
					        return os.path.normcase(self.file[-3:]) == ".py"
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def listclasses(self):
 | 
				
			||||||
 | 
					        dir, file = os.path.split(self.file)
 | 
				
			||||||
 | 
					        name, ext = os.path.splitext(file)
 | 
				
			||||||
 | 
					        if os.path.normcase(ext) != ".py":
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            dict = pyclbr.readmodule_ex(name, [dir] + sys.path)
 | 
				
			||||||
 | 
					        except ImportError, msg:
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					        items = []
 | 
				
			||||||
 | 
					        self.classes = {}
 | 
				
			||||||
 | 
					        for key, cl in dict.items():
 | 
				
			||||||
 | 
					            if cl.module == name:
 | 
				
			||||||
 | 
					                s = key
 | 
				
			||||||
 | 
					                if cl.super:
 | 
				
			||||||
 | 
					                    supers = []
 | 
				
			||||||
 | 
					                    for sup in cl.super:
 | 
				
			||||||
 | 
					                        if type(sup) is type(''):
 | 
				
			||||||
 | 
					                            sname = sup
 | 
				
			||||||
 | 
					                        else:
 | 
				
			||||||
 | 
					                            sname = sup.name
 | 
				
			||||||
 | 
					                            if sup.module != cl.module:
 | 
				
			||||||
 | 
					                                sname = "%s.%s" % (sup.module, sname)
 | 
				
			||||||
 | 
					                        supers.append(sname)
 | 
				
			||||||
 | 
					                    s = s + "(%s)" % string.join(supers, ", ")
 | 
				
			||||||
 | 
					                items.append((cl.lineno, s))
 | 
				
			||||||
 | 
					                self.classes[s] = cl
 | 
				
			||||||
 | 
					        items.sort()
 | 
				
			||||||
 | 
					        list = []
 | 
				
			||||||
 | 
					        for item, s in items:
 | 
				
			||||||
 | 
					            list.append(s)
 | 
				
			||||||
 | 
					        return list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ClassBrowserTreeItem(TreeItem):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, name, classes, file):
 | 
				
			||||||
 | 
					        self.name = name
 | 
				
			||||||
 | 
					        self.classes = classes
 | 
				
			||||||
 | 
					        self.file = file
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.cl = self.classes[self.name]
 | 
				
			||||||
 | 
					        except (IndexError, KeyError):
 | 
				
			||||||
 | 
					            self.cl = None
 | 
				
			||||||
 | 
					        self.isfunction = isinstance(self.cl, pyclbr.Function)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetText(self):
 | 
				
			||||||
 | 
					        if self.isfunction:
 | 
				
			||||||
 | 
					            return "def " + self.name + "(...)"
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return "class " + self.name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetIconName(self):
 | 
				
			||||||
 | 
					        if self.isfunction:
 | 
				
			||||||
 | 
					            return "python"
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return "folder"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def IsExpandable(self):
 | 
				
			||||||
 | 
					        if self.cl:
 | 
				
			||||||
 | 
					            return not not self.cl.methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetSubList(self):
 | 
				
			||||||
 | 
					        if not self.cl:
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					        sublist = []
 | 
				
			||||||
 | 
					        for name in self.listmethods():
 | 
				
			||||||
 | 
					            item = MethodBrowserTreeItem(name, self.cl, self.file)
 | 
				
			||||||
 | 
					            sublist.append(item)
 | 
				
			||||||
 | 
					        return sublist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def OnDoubleClick(self):
 | 
				
			||||||
 | 
					        if not os.path.exists(self.file):
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        edit = PyShell.flist.open(self.file)
 | 
				
			||||||
 | 
					        if hasattr(self.cl, 'lineno'):
 | 
				
			||||||
 | 
					            lineno = self.cl.lineno
 | 
				
			||||||
 | 
					            edit.gotoline(lineno)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def listmethods(self):
 | 
				
			||||||
 | 
					        if not self.cl:
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					        items = []
 | 
				
			||||||
 | 
					        for name, lineno in self.cl.methods.items():
 | 
				
			||||||
 | 
					            items.append((lineno, name))
 | 
				
			||||||
 | 
					        items.sort()
 | 
				
			||||||
 | 
					        list = []
 | 
				
			||||||
 | 
					        for item, name in items:
 | 
				
			||||||
 | 
					            list.append(name)
 | 
				
			||||||
 | 
					        return list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MethodBrowserTreeItem(TreeItem):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, name, cl, file):
 | 
				
			||||||
 | 
					        self.name = name
 | 
				
			||||||
 | 
					        self.cl = cl
 | 
				
			||||||
 | 
					        self.file = file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetText(self):
 | 
				
			||||||
 | 
					        return "def " + self.name + "(...)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetIconName(self):
 | 
				
			||||||
 | 
					        return "python" # XXX
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def IsExpandable(self):
 | 
				
			||||||
 | 
					        return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def OnDoubleClick(self):
 | 
				
			||||||
 | 
					        if not os.path.exists(self.file):
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        edit = PyShell.flist.open(self.file)
 | 
				
			||||||
 | 
					        edit.gotoline(self.cl.methods[self.name])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        file = __file__
 | 
				
			||||||
 | 
					    except NameError:
 | 
				
			||||||
 | 
					        file = sys.argv[0]
 | 
				
			||||||
 | 
					        if sys.argv[1:]:
 | 
				
			||||||
 | 
					            file = sys.argv[1]
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            file = sys.argv[0]
 | 
				
			||||||
 | 
					    dir, file = os.path.split(file)
 | 
				
			||||||
 | 
					    name = os.path.splitext(file)[0]
 | 
				
			||||||
 | 
					    ClassBrowser(PyShell.flist, name, [dir])
 | 
				
			||||||
 | 
					    if sys.stdin is sys.__stdin__:
 | 
				
			||||||
 | 
					        mainloop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										234
									
								
								Lib/idlelib/ColorDelegator.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										234
									
								
								Lib/idlelib/ColorDelegator.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,234 @@
 | 
				
			||||||
 | 
					import time
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import keyword
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					from Delegator import Delegator
 | 
				
			||||||
 | 
					from IdleConf import idleconf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<toggle-auto-coloring>>
 | 
				
			||||||
 | 
					#$ win <Control-slash>
 | 
				
			||||||
 | 
					#$ unix <Control-slash>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__debug__ = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def any(name, list):
 | 
				
			||||||
 | 
					    return "(?P<%s>" % name + string.join(list, "|") + ")"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def make_pat():
 | 
				
			||||||
 | 
					    kw = r"\b" + any("KEYWORD", keyword.kwlist) + r"\b"
 | 
				
			||||||
 | 
					    comment = any("COMMENT", [r"#[^\n]*"])
 | 
				
			||||||
 | 
					    sqstring = r"(\b[rR])?'[^'\\\n]*(\\.[^'\\\n]*)*'?"
 | 
				
			||||||
 | 
					    dqstring = r'(\b[rR])?"[^"\\\n]*(\\.[^"\\\n]*)*"?'
 | 
				
			||||||
 | 
					    sq3string = r"(\b[rR])?'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?"
 | 
				
			||||||
 | 
					    dq3string = r'(\b[rR])?"""[^"\\]*((\\.|"(?!""))[^"\\]*)*(""")?'
 | 
				
			||||||
 | 
					    string = any("STRING", [sq3string, dq3string, sqstring, dqstring])
 | 
				
			||||||
 | 
					    return kw + "|" + comment + "|" + string + "|" + any("SYNC", [r"\n"])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					prog = re.compile(make_pat(), re.S)
 | 
				
			||||||
 | 
					idprog = re.compile(r"\s+(\w+)", re.S)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ColorDelegator(Delegator):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        Delegator.__init__(self)
 | 
				
			||||||
 | 
					        self.prog = prog
 | 
				
			||||||
 | 
					        self.idprog = idprog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setdelegate(self, delegate):
 | 
				
			||||||
 | 
					        if self.delegate is not None:
 | 
				
			||||||
 | 
					            self.unbind("<<toggle-auto-coloring>>")
 | 
				
			||||||
 | 
					        Delegator.setdelegate(self, delegate)
 | 
				
			||||||
 | 
					        if delegate is not None:
 | 
				
			||||||
 | 
					            self.config_colors()
 | 
				
			||||||
 | 
					            self.bind("<<toggle-auto-coloring>>", self.toggle_colorize_event)
 | 
				
			||||||
 | 
					            self.notify_range("1.0", "end")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def config_colors(self):
 | 
				
			||||||
 | 
					        for tag, cnf in self.tagdefs.items():
 | 
				
			||||||
 | 
					            if cnf:
 | 
				
			||||||
 | 
					                apply(self.tag_configure, (tag,), cnf)
 | 
				
			||||||
 | 
					        self.tag_raise('sel')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cconf = idleconf.getsection('Colors')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tagdefs = {
 | 
				
			||||||
 | 
					        "COMMENT": cconf.getcolor("comment"),
 | 
				
			||||||
 | 
					        "KEYWORD": cconf.getcolor("keyword"),
 | 
				
			||||||
 | 
					        "STRING": cconf.getcolor("string"),
 | 
				
			||||||
 | 
					        "DEFINITION": cconf.getcolor("definition"),
 | 
				
			||||||
 | 
					        "SYNC": cconf.getcolor("sync"),
 | 
				
			||||||
 | 
					        "TODO": cconf.getcolor("todo"),
 | 
				
			||||||
 | 
					        "BREAK": cconf.getcolor("break"),
 | 
				
			||||||
 | 
					        # The following is used by ReplaceDialog:
 | 
				
			||||||
 | 
					        "hit": cconf.getcolor("hit"),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def insert(self, index, chars, tags=None):
 | 
				
			||||||
 | 
					        index = self.index(index)
 | 
				
			||||||
 | 
					        self.delegate.insert(index, chars, tags)
 | 
				
			||||||
 | 
					        self.notify_range(index, index + "+%dc" % len(chars))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete(self, index1, index2=None):
 | 
				
			||||||
 | 
					        index1 = self.index(index1)
 | 
				
			||||||
 | 
					        self.delegate.delete(index1, index2)
 | 
				
			||||||
 | 
					        self.notify_range(index1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    after_id = None
 | 
				
			||||||
 | 
					    allow_colorizing = 1
 | 
				
			||||||
 | 
					    colorizing = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def notify_range(self, index1, index2=None):
 | 
				
			||||||
 | 
					        self.tag_add("TODO", index1, index2)
 | 
				
			||||||
 | 
					        if self.after_id:
 | 
				
			||||||
 | 
					            if __debug__: print "colorizing already scheduled"
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if self.colorizing:
 | 
				
			||||||
 | 
					            self.stop_colorizing = 1
 | 
				
			||||||
 | 
					            if __debug__: print "stop colorizing"
 | 
				
			||||||
 | 
					        if self.allow_colorizing:
 | 
				
			||||||
 | 
					            if __debug__: print "schedule colorizing"
 | 
				
			||||||
 | 
					            self.after_id = self.after(1, self.recolorize)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    close_when_done = None # Window to be closed when done colorizing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self, close_when_done=None):
 | 
				
			||||||
 | 
					        if self.after_id:
 | 
				
			||||||
 | 
					            after_id = self.after_id
 | 
				
			||||||
 | 
					            self.after_id = None
 | 
				
			||||||
 | 
					            if __debug__: print "cancel scheduled recolorizer"
 | 
				
			||||||
 | 
					            self.after_cancel(after_id)
 | 
				
			||||||
 | 
					        self.allow_colorizing = 0
 | 
				
			||||||
 | 
					        self.stop_colorizing = 1
 | 
				
			||||||
 | 
					        if close_when_done:
 | 
				
			||||||
 | 
					            if not self.colorizing:
 | 
				
			||||||
 | 
					                close_when_done.destroy()
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                self.close_when_done = close_when_done
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def toggle_colorize_event(self, event):
 | 
				
			||||||
 | 
					        if self.after_id:
 | 
				
			||||||
 | 
					            after_id = self.after_id
 | 
				
			||||||
 | 
					            self.after_id = None
 | 
				
			||||||
 | 
					            if __debug__: print "cancel scheduled recolorizer"
 | 
				
			||||||
 | 
					            self.after_cancel(after_id)
 | 
				
			||||||
 | 
					        if self.allow_colorizing and self.colorizing:
 | 
				
			||||||
 | 
					            if __debug__: print "stop colorizing"
 | 
				
			||||||
 | 
					            self.stop_colorizing = 1
 | 
				
			||||||
 | 
					        self.allow_colorizing = not self.allow_colorizing
 | 
				
			||||||
 | 
					        if self.allow_colorizing and not self.colorizing:
 | 
				
			||||||
 | 
					            self.after_id = self.after(1, self.recolorize)
 | 
				
			||||||
 | 
					        if __debug__:
 | 
				
			||||||
 | 
					            print "auto colorizing turned", self.allow_colorizing and "on" or "off"
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def recolorize(self):
 | 
				
			||||||
 | 
					        self.after_id = None
 | 
				
			||||||
 | 
					        if not self.delegate:
 | 
				
			||||||
 | 
					            if __debug__: print "no delegate"
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if not self.allow_colorizing:
 | 
				
			||||||
 | 
					            if __debug__: print "auto colorizing is off"
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if self.colorizing:
 | 
				
			||||||
 | 
					            if __debug__: print "already colorizing"
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.stop_colorizing = 0
 | 
				
			||||||
 | 
					            self.colorizing = 1
 | 
				
			||||||
 | 
					            if __debug__: print "colorizing..."
 | 
				
			||||||
 | 
					            t0 = time.clock()
 | 
				
			||||||
 | 
					            self.recolorize_main()
 | 
				
			||||||
 | 
					            t1 = time.clock()
 | 
				
			||||||
 | 
					            if __debug__: print "%.3f seconds" % (t1-t0)
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            self.colorizing = 0
 | 
				
			||||||
 | 
					        if self.allow_colorizing and self.tag_nextrange("TODO", "1.0"):
 | 
				
			||||||
 | 
					            if __debug__: print "reschedule colorizing"
 | 
				
			||||||
 | 
					            self.after_id = self.after(1, self.recolorize)
 | 
				
			||||||
 | 
					        if self.close_when_done:
 | 
				
			||||||
 | 
					            top = self.close_when_done
 | 
				
			||||||
 | 
					            self.close_when_done = None
 | 
				
			||||||
 | 
					            top.destroy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def recolorize_main(self):
 | 
				
			||||||
 | 
					        next = "1.0"
 | 
				
			||||||
 | 
					        while 1:
 | 
				
			||||||
 | 
					            item = self.tag_nextrange("TODO", next)
 | 
				
			||||||
 | 
					            if not item:
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            head, tail = item
 | 
				
			||||||
 | 
					            self.tag_remove("SYNC", head, tail)
 | 
				
			||||||
 | 
					            item = self.tag_prevrange("SYNC", head)
 | 
				
			||||||
 | 
					            if item:
 | 
				
			||||||
 | 
					                head = item[1]
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                head = "1.0"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            chars = ""
 | 
				
			||||||
 | 
					            next = head
 | 
				
			||||||
 | 
					            lines_to_get = 1
 | 
				
			||||||
 | 
					            ok = 0
 | 
				
			||||||
 | 
					            while not ok:
 | 
				
			||||||
 | 
					                mark = next
 | 
				
			||||||
 | 
					                next = self.index(mark + "+%d lines linestart" %
 | 
				
			||||||
 | 
					                                         lines_to_get)
 | 
				
			||||||
 | 
					                lines_to_get = min(lines_to_get * 2, 100)
 | 
				
			||||||
 | 
					                ok = "SYNC" in self.tag_names(next + "-1c")
 | 
				
			||||||
 | 
					                line = self.get(mark, next)
 | 
				
			||||||
 | 
					                ##print head, "get", mark, next, "->", `line`
 | 
				
			||||||
 | 
					                if not line:
 | 
				
			||||||
 | 
					                    return
 | 
				
			||||||
 | 
					                for tag in self.tagdefs.keys():
 | 
				
			||||||
 | 
					                    self.tag_remove(tag, mark, next)
 | 
				
			||||||
 | 
					                chars = chars + line
 | 
				
			||||||
 | 
					                m = self.prog.search(chars)
 | 
				
			||||||
 | 
					                while m:
 | 
				
			||||||
 | 
					                    for key, value in m.groupdict().items():
 | 
				
			||||||
 | 
					                        if value:
 | 
				
			||||||
 | 
					                            a, b = m.span(key)
 | 
				
			||||||
 | 
					                            self.tag_add(key,
 | 
				
			||||||
 | 
					                                         head + "+%dc" % a,
 | 
				
			||||||
 | 
					                                         head + "+%dc" % b)
 | 
				
			||||||
 | 
					                            if value in ("def", "class"):
 | 
				
			||||||
 | 
					                                m1 = self.idprog.match(chars, b)
 | 
				
			||||||
 | 
					                                if m1:
 | 
				
			||||||
 | 
					                                    a, b = m1.span(1)
 | 
				
			||||||
 | 
					                                    self.tag_add("DEFINITION",
 | 
				
			||||||
 | 
					                                                 head + "+%dc" % a,
 | 
				
			||||||
 | 
					                                                 head + "+%dc" % b)
 | 
				
			||||||
 | 
					                    m = self.prog.search(chars, m.end())
 | 
				
			||||||
 | 
					                if "SYNC" in self.tag_names(next + "-1c"):
 | 
				
			||||||
 | 
					                    head = next
 | 
				
			||||||
 | 
					                    chars = ""
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    ok = 0
 | 
				
			||||||
 | 
					                if not ok:
 | 
				
			||||||
 | 
					                    # We're in an inconsistent state, and the call to
 | 
				
			||||||
 | 
					                    # update may tell us to stop.  It may also change
 | 
				
			||||||
 | 
					                    # the correct value for "next" (since this is a
 | 
				
			||||||
 | 
					                    # line.col string, not a true mark).  So leave a
 | 
				
			||||||
 | 
					                    # crumb telling the next invocation to resume here
 | 
				
			||||||
 | 
					                    # in case update tells us to leave.
 | 
				
			||||||
 | 
					                    self.tag_add("TODO", next)
 | 
				
			||||||
 | 
					                self.update()
 | 
				
			||||||
 | 
					                if self.stop_colorizing:
 | 
				
			||||||
 | 
					                    if __debug__: print "colorizing stopped"
 | 
				
			||||||
 | 
					                    return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    from Percolator import Percolator
 | 
				
			||||||
 | 
					    root = Tk()
 | 
				
			||||||
 | 
					    root.wm_protocol("WM_DELETE_WINDOW", root.quit)
 | 
				
			||||||
 | 
					    text = Text(background="white")
 | 
				
			||||||
 | 
					    text.pack(expand=1, fill="both")
 | 
				
			||||||
 | 
					    text.focus_set()
 | 
				
			||||||
 | 
					    p = Percolator(text)
 | 
				
			||||||
 | 
					    d = ColorDelegator()
 | 
				
			||||||
 | 
					    p.insertfilter(d)
 | 
				
			||||||
 | 
					    root.mainloop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										382
									
								
								Lib/idlelib/ConfigParser.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										382
									
								
								Lib/idlelib/ConfigParser.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,382 @@
 | 
				
			||||||
 | 
					"""Configuration file parser.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A setup file consists of sections, lead by a "[section]" header,
 | 
				
			||||||
 | 
					and followed by "name: value" entries, with continuations and such in
 | 
				
			||||||
 | 
					the style of RFC 822.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The option values can contain format strings which refer to other values in
 | 
				
			||||||
 | 
					the same section, or values in a special [DEFAULT] section.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    something: %(dir)s/whatever
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					would resolve the "%(dir)s" to the value of dir.  All reference
 | 
				
			||||||
 | 
					expansions are done late, on demand.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Intrinsic defaults can be specified by passing them into the
 | 
				
			||||||
 | 
					ConfigParser constructor as a dictionary.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ConfigParser -- responsible for for parsing a list of
 | 
				
			||||||
 | 
					                configuration files, and managing the parsed database.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    methods:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    __init__(defaults=None)
 | 
				
			||||||
 | 
					        create the parser and specify a dictionary of intrinsic defaults.  The
 | 
				
			||||||
 | 
					        keys must be strings, the values must be appropriate for %()s string
 | 
				
			||||||
 | 
					        interpolation.  Note that `__name__' is always an intrinsic default;
 | 
				
			||||||
 | 
					        it's value is the section's name.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sections()
 | 
				
			||||||
 | 
					        return all the configuration section names, sans DEFAULT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    has_section(section)
 | 
				
			||||||
 | 
					        return whether the given section exists
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    options(section)
 | 
				
			||||||
 | 
					        return list of configuration options for the named section
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    has_option(section, option)
 | 
				
			||||||
 | 
					        return whether the given section has the given option
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    read(filenames)
 | 
				
			||||||
 | 
					        read and parse the list of named configuration files, given by
 | 
				
			||||||
 | 
					        name.  A single filename is also allowed.  Non-existing files
 | 
				
			||||||
 | 
					        are ignored.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    readfp(fp, filename=None)
 | 
				
			||||||
 | 
					        read and parse one configuration file, given as a file object.
 | 
				
			||||||
 | 
					        The filename defaults to fp.name; it is only used in error
 | 
				
			||||||
 | 
					        messages (if fp has no `name' attribute, the string `<???>' is used).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    get(section, option, raw=0, vars=None)
 | 
				
			||||||
 | 
					        return a string value for the named option.  All % interpolations are
 | 
				
			||||||
 | 
					        expanded in the return values, based on the defaults passed into the
 | 
				
			||||||
 | 
					        constructor and the DEFAULT section.  Additional substitutions may be
 | 
				
			||||||
 | 
					        provided using the `vars' argument, which must be a dictionary whose
 | 
				
			||||||
 | 
					        contents override any pre-existing defaults.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getint(section, options)
 | 
				
			||||||
 | 
					        like get(), but convert value to an integer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getfloat(section, options)
 | 
				
			||||||
 | 
					        like get(), but convert value to a float
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    getboolean(section, options)
 | 
				
			||||||
 | 
					        like get(), but convert value to a boolean (currently defined as 0 or
 | 
				
			||||||
 | 
					        1, only)
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					DEFAULTSECT = "DEFAULT"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# exception classes
 | 
				
			||||||
 | 
					class Error:
 | 
				
			||||||
 | 
					    def __init__(self, msg=''):
 | 
				
			||||||
 | 
					        self._msg = msg
 | 
				
			||||||
 | 
					    def __repr__(self):
 | 
				
			||||||
 | 
					        return self._msg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NoSectionError(Error):
 | 
				
			||||||
 | 
					    def __init__(self, section):
 | 
				
			||||||
 | 
					        Error.__init__(self, 'No section: %s' % section)
 | 
				
			||||||
 | 
					        self.section = section
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DuplicateSectionError(Error):
 | 
				
			||||||
 | 
					    def __init__(self, section):
 | 
				
			||||||
 | 
					        Error.__init__(self, "Section %s already exists" % section)
 | 
				
			||||||
 | 
					        self.section = section
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NoOptionError(Error):
 | 
				
			||||||
 | 
					    def __init__(self, option, section):
 | 
				
			||||||
 | 
					        Error.__init__(self, "No option `%s' in section: %s" %
 | 
				
			||||||
 | 
					                       (option, section))
 | 
				
			||||||
 | 
					        self.option = option
 | 
				
			||||||
 | 
					        self.section = section
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InterpolationError(Error):
 | 
				
			||||||
 | 
					    def __init__(self, reference, option, section, rawval):
 | 
				
			||||||
 | 
					        Error.__init__(self,
 | 
				
			||||||
 | 
					                       "Bad value substitution:\n"
 | 
				
			||||||
 | 
					                       "\tsection: [%s]\n"
 | 
				
			||||||
 | 
					                       "\toption : %s\n"
 | 
				
			||||||
 | 
					                       "\tkey    : %s\n"
 | 
				
			||||||
 | 
					                       "\trawval : %s\n"
 | 
				
			||||||
 | 
					                       % (section, option, reference, rawval))
 | 
				
			||||||
 | 
					        self.reference = reference
 | 
				
			||||||
 | 
					        self.option = option
 | 
				
			||||||
 | 
					        self.section = section
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MissingSectionHeaderError(Error):
 | 
				
			||||||
 | 
					    def __init__(self, filename, lineno, line):
 | 
				
			||||||
 | 
					        Error.__init__(
 | 
				
			||||||
 | 
					            self,
 | 
				
			||||||
 | 
					            'File contains no section headers.\nfile: %s, line: %d\n%s' %
 | 
				
			||||||
 | 
					            (filename, lineno, line))
 | 
				
			||||||
 | 
					        self.filename = filename
 | 
				
			||||||
 | 
					        self.lineno = lineno
 | 
				
			||||||
 | 
					        self.line = line
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ParsingError(Error):
 | 
				
			||||||
 | 
					    def __init__(self, filename):
 | 
				
			||||||
 | 
					        Error.__init__(self, 'File contains parsing errors: %s' % filename)
 | 
				
			||||||
 | 
					        self.filename = filename
 | 
				
			||||||
 | 
					        self.errors = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def append(self, lineno, line):
 | 
				
			||||||
 | 
					        self.errors.append((lineno, line))
 | 
				
			||||||
 | 
					        self._msg = self._msg + '\n\t[line %2d]: %s' % (lineno, line)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ConfigParser:
 | 
				
			||||||
 | 
					    def __init__(self, defaults=None):
 | 
				
			||||||
 | 
					        self.__sections = {}
 | 
				
			||||||
 | 
					        if defaults is None:
 | 
				
			||||||
 | 
					            self.__defaults = {}
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.__defaults = defaults
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def defaults(self):
 | 
				
			||||||
 | 
					        return self.__defaults
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def sections(self):
 | 
				
			||||||
 | 
					        """Return a list of section names, excluding [DEFAULT]"""
 | 
				
			||||||
 | 
					        # self.__sections will never have [DEFAULT] in it
 | 
				
			||||||
 | 
					        return self.__sections.keys()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add_section(self, section):
 | 
				
			||||||
 | 
					        """Create a new section in the configuration.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Raise DuplicateSectionError if a section by the specified name
 | 
				
			||||||
 | 
					        already exists.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if self.__sections.has_key(section):
 | 
				
			||||||
 | 
					            raise DuplicateSectionError(section)
 | 
				
			||||||
 | 
					        self.__sections[section] = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def has_section(self, section):
 | 
				
			||||||
 | 
					        """Indicate whether the named section is present in the configuration.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The DEFAULT section is not acknowledged.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        return self.__sections.has_key(section)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def options(self, section):
 | 
				
			||||||
 | 
					        """Return a list of option names for the given section name."""
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            opts = self.__sections[section].copy()
 | 
				
			||||||
 | 
					        except KeyError:
 | 
				
			||||||
 | 
					            raise NoSectionError(section)
 | 
				
			||||||
 | 
					        opts.update(self.__defaults)
 | 
				
			||||||
 | 
					        return opts.keys()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def has_option(self, section, option):
 | 
				
			||||||
 | 
					        """Return whether the given section has the given option."""
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            opts = self.__sections[section]
 | 
				
			||||||
 | 
					        except KeyError:
 | 
				
			||||||
 | 
					            raise NoSectionError(section)
 | 
				
			||||||
 | 
					        return opts.has_key(option)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def read(self, filenames):
 | 
				
			||||||
 | 
					        """Read and parse a filename or a list of filenames.
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        Files that cannot be opened are silently ignored; this is
 | 
				
			||||||
 | 
					        designed so that you can specify a list of potential
 | 
				
			||||||
 | 
					        configuration file locations (e.g. current directory, user's
 | 
				
			||||||
 | 
					        home directory, systemwide directory), and all existing
 | 
				
			||||||
 | 
					        configuration files in the list will be read.  A single
 | 
				
			||||||
 | 
					        filename may also be given.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if type(filenames) is type(''):
 | 
				
			||||||
 | 
					            filenames = [filenames]
 | 
				
			||||||
 | 
					        for filename in filenames:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                fp = open(filename)
 | 
				
			||||||
 | 
					            except IOError:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            self.__read(fp, filename)
 | 
				
			||||||
 | 
					            fp.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def readfp(self, fp, filename=None):
 | 
				
			||||||
 | 
					        """Like read() but the argument must be a file-like object.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The `fp' argument must have a `readline' method.  Optional
 | 
				
			||||||
 | 
					        second argument is the `filename', which if not given, is
 | 
				
			||||||
 | 
					        taken from fp.name.  If fp has no `name' attribute, `<???>' is
 | 
				
			||||||
 | 
					        used.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if filename is None:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                filename = fp.name
 | 
				
			||||||
 | 
					            except AttributeError:
 | 
				
			||||||
 | 
					                filename = '<???>'
 | 
				
			||||||
 | 
					        self.__read(fp, filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get(self, section, option, raw=0, vars=None):
 | 
				
			||||||
 | 
					        """Get an option value for a given section.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        All % interpolations are expanded in the return values, based on the
 | 
				
			||||||
 | 
					        defaults passed into the constructor, unless the optional argument
 | 
				
			||||||
 | 
					        `raw' is true.  Additional substitutions may be provided using the
 | 
				
			||||||
 | 
					        `vars' argument, which must be a dictionary whose contents overrides
 | 
				
			||||||
 | 
					        any pre-existing defaults.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The section DEFAULT is special.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            sectdict = self.__sections[section].copy()
 | 
				
			||||||
 | 
					        except KeyError:
 | 
				
			||||||
 | 
					            if section == DEFAULTSECT:
 | 
				
			||||||
 | 
					                sectdict = {}
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                raise NoSectionError(section)
 | 
				
			||||||
 | 
					        d = self.__defaults.copy()
 | 
				
			||||||
 | 
					        d.update(sectdict)
 | 
				
			||||||
 | 
					        # Update with the entry specific variables
 | 
				
			||||||
 | 
					        if vars:
 | 
				
			||||||
 | 
					            d.update(vars)
 | 
				
			||||||
 | 
					        option = self.optionxform(option)
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            rawval = d[option]
 | 
				
			||||||
 | 
					        except KeyError:
 | 
				
			||||||
 | 
					            raise NoOptionError(option, section)
 | 
				
			||||||
 | 
					        # do the string interpolation
 | 
				
			||||||
 | 
					        if raw:
 | 
				
			||||||
 | 
					            return rawval
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        value = rawval                  # Make it a pretty variable name
 | 
				
			||||||
 | 
					        depth = 0                       
 | 
				
			||||||
 | 
					        while depth < 10:               # Loop through this until it's done
 | 
				
			||||||
 | 
					            depth = depth + 1
 | 
				
			||||||
 | 
					            if string.find(value, "%(") >= 0:
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    value = value % d
 | 
				
			||||||
 | 
					                except KeyError, key:
 | 
				
			||||||
 | 
					                    raise InterpolationError(key, option, section, rawval)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                return value
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def __get(self, section, conv, option):
 | 
				
			||||||
 | 
					        return conv(self.get(section, option))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getint(self, section, option):
 | 
				
			||||||
 | 
					        return self.__get(section, string.atoi, option)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getfloat(self, section, option):
 | 
				
			||||||
 | 
					        return self.__get(section, string.atof, option)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getboolean(self, section, option):
 | 
				
			||||||
 | 
					        v = self.get(section, option)
 | 
				
			||||||
 | 
					        val = string.atoi(v)
 | 
				
			||||||
 | 
					        if val not in (0, 1):
 | 
				
			||||||
 | 
					            raise ValueError, 'Not a boolean: %s' % v
 | 
				
			||||||
 | 
					        return val
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def optionxform(self, optionstr):
 | 
				
			||||||
 | 
					        return string.lower(optionstr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    # Regular expressions for parsing section headers and options.  Note a
 | 
				
			||||||
 | 
					    # slight semantic change from the previous version, because of the use
 | 
				
			||||||
 | 
					    # of \w, _ is allowed in section header names.
 | 
				
			||||||
 | 
					    SECTCRE = re.compile(
 | 
				
			||||||
 | 
					        r'\['                                 # [
 | 
				
			||||||
 | 
					        r'(?P<header>[-\w_.*,(){}]+)'         # a lot of stuff found by IvL
 | 
				
			||||||
 | 
					        r'\]'                                 # ]
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					    OPTCRE = re.compile(
 | 
				
			||||||
 | 
					        r'(?P<option>[-\w_.*,(){}]+)'         # a lot of stuff found by IvL
 | 
				
			||||||
 | 
					        r'[ \t]*(?P<vi>[:=])[ \t]*'           # any number of space/tab,
 | 
				
			||||||
 | 
					                                              # followed by separator
 | 
				
			||||||
 | 
					                                              # (either : or =), followed
 | 
				
			||||||
 | 
					                                              # by any # space/tab
 | 
				
			||||||
 | 
					        r'(?P<value>.*)$'                     # everything up to eol
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __read(self, fp, fpname):
 | 
				
			||||||
 | 
					        """Parse a sectioned setup file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The sections in setup file contains a title line at the top,
 | 
				
			||||||
 | 
					        indicated by a name in square brackets (`[]'), plus key/value
 | 
				
			||||||
 | 
					        options lines, indicated by `name: value' format lines.
 | 
				
			||||||
 | 
					        Continuation are represented by an embedded newline then
 | 
				
			||||||
 | 
					        leading whitespace.  Blank lines, lines beginning with a '#',
 | 
				
			||||||
 | 
					        and just about everything else is ignored.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        cursect = None                            # None, or a dictionary
 | 
				
			||||||
 | 
					        optname = None
 | 
				
			||||||
 | 
					        lineno = 0
 | 
				
			||||||
 | 
					        e = None                                  # None, or an exception
 | 
				
			||||||
 | 
					        while 1:
 | 
				
			||||||
 | 
					            line = fp.readline()
 | 
				
			||||||
 | 
					            if not line:
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            lineno = lineno + 1
 | 
				
			||||||
 | 
					            # comment or blank line?
 | 
				
			||||||
 | 
					            if string.strip(line) == '' or line[0] in '#;':
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            if string.lower(string.split(line)[0]) == 'rem' \
 | 
				
			||||||
 | 
					               and line[0] in "rR":      # no leading whitespace
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            # continuation line?
 | 
				
			||||||
 | 
					            if line[0] in ' \t' and cursect is not None and optname:
 | 
				
			||||||
 | 
					                value = string.strip(line)
 | 
				
			||||||
 | 
					                if value:
 | 
				
			||||||
 | 
					                    cursect[optname] = cursect[optname] + '\n ' + value
 | 
				
			||||||
 | 
					            # a section header or option header?
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                # is it a section header?
 | 
				
			||||||
 | 
					                mo = self.SECTCRE.match(line)
 | 
				
			||||||
 | 
					                if mo:
 | 
				
			||||||
 | 
					                    sectname = mo.group('header')
 | 
				
			||||||
 | 
					                    if self.__sections.has_key(sectname):
 | 
				
			||||||
 | 
					                        cursect = self.__sections[sectname]
 | 
				
			||||||
 | 
					                    elif sectname == DEFAULTSECT:
 | 
				
			||||||
 | 
					                        cursect = self.__defaults
 | 
				
			||||||
 | 
					                    else:
 | 
				
			||||||
 | 
					                        cursect = {'__name__': sectname}
 | 
				
			||||||
 | 
					                        self.__sections[sectname] = cursect
 | 
				
			||||||
 | 
					                    # So sections can't start with a continuation line
 | 
				
			||||||
 | 
					                    optname = None
 | 
				
			||||||
 | 
					                # no section header in the file?
 | 
				
			||||||
 | 
					                elif cursect is None:
 | 
				
			||||||
 | 
					                    raise MissingSectionHeaderError(fpname, lineno, `line`)
 | 
				
			||||||
 | 
					                # an option line?
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    mo = self.OPTCRE.match(line)
 | 
				
			||||||
 | 
					                    if mo:
 | 
				
			||||||
 | 
					                        optname, vi, optval = mo.group('option', 'vi', 'value')
 | 
				
			||||||
 | 
					                        optname = string.lower(optname)
 | 
				
			||||||
 | 
					                        if vi in ('=', ':') and ';' in optval:
 | 
				
			||||||
 | 
					                            # ';' is a comment delimiter only if it follows
 | 
				
			||||||
 | 
					                            # a spacing character
 | 
				
			||||||
 | 
					                            pos = string.find(optval, ';')
 | 
				
			||||||
 | 
					                            if pos and optval[pos-1] in string.whitespace:
 | 
				
			||||||
 | 
					                                optval = optval[:pos]
 | 
				
			||||||
 | 
					                        optval = string.strip(optval)
 | 
				
			||||||
 | 
					                        # allow empty values
 | 
				
			||||||
 | 
					                        if optval == '""':
 | 
				
			||||||
 | 
					                            optval = ''
 | 
				
			||||||
 | 
					                        cursect[optname] = optval
 | 
				
			||||||
 | 
					                    else:
 | 
				
			||||||
 | 
					                        # a non-fatal parsing error occurred.  set up the
 | 
				
			||||||
 | 
					                        # exception but keep going. the exception will be
 | 
				
			||||||
 | 
					                        # raised at the end of the file and will contain a
 | 
				
			||||||
 | 
					                        # list of all bogus lines
 | 
				
			||||||
 | 
					                        if not e:
 | 
				
			||||||
 | 
					                            e = ParsingError(fpname)
 | 
				
			||||||
 | 
					                        e.append(lineno, `line`)
 | 
				
			||||||
 | 
					        # if any parsing errors occurred, raise an exception
 | 
				
			||||||
 | 
					        if e:
 | 
				
			||||||
 | 
					            raise e
 | 
				
			||||||
							
								
								
									
										308
									
								
								Lib/idlelib/Debugger.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										308
									
								
								Lib/idlelib/Debugger.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,308 @@
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import bdb
 | 
				
			||||||
 | 
					import traceback
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					from WindowList import ListedToplevel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import StackViewer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Debugger(bdb.Bdb):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    interacting = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vstack = vsource = vlocals = vglobals = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, pyshell):
 | 
				
			||||||
 | 
					        bdb.Bdb.__init__(self)
 | 
				
			||||||
 | 
					        self.pyshell = pyshell
 | 
				
			||||||
 | 
					        self.make_gui()
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def canonic(self, filename):
 | 
				
			||||||
 | 
					        # Canonicalize filename -- called by Bdb
 | 
				
			||||||
 | 
					        return os.path.normcase(os.path.abspath(filename))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self, event=None):
 | 
				
			||||||
 | 
					        if self.interacting:
 | 
				
			||||||
 | 
					            self.top.bell()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if self.stackviewer:
 | 
				
			||||||
 | 
					            self.stackviewer.close(); self.stackviewer = None
 | 
				
			||||||
 | 
					        self.pyshell.close_debugger()
 | 
				
			||||||
 | 
					        self.top.destroy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run(self, *args):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.interacting = 1
 | 
				
			||||||
 | 
					            return apply(bdb.Bdb.run, (self,) + args)
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            self.interacting = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def user_line(self, frame):
 | 
				
			||||||
 | 
					        self.interaction(frame)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def user_return(self, frame, rv):
 | 
				
			||||||
 | 
					        # XXX show rv?
 | 
				
			||||||
 | 
					        ##self.interaction(frame)
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def user_exception(self, frame, info):
 | 
				
			||||||
 | 
					        self.interaction(frame, info)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def make_gui(self):
 | 
				
			||||||
 | 
					        pyshell = self.pyshell
 | 
				
			||||||
 | 
					        self.flist = pyshell.flist
 | 
				
			||||||
 | 
					        self.root = root = pyshell.root
 | 
				
			||||||
 | 
					        self.top = top =ListedToplevel(root)
 | 
				
			||||||
 | 
					        self.top.wm_title("Debug Control")
 | 
				
			||||||
 | 
					        self.top.wm_iconname("Debug")
 | 
				
			||||||
 | 
					        top.wm_protocol("WM_DELETE_WINDOW", self.close)
 | 
				
			||||||
 | 
					        self.top.bind("<Escape>", self.close)
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        self.bframe = bframe = Frame(top)
 | 
				
			||||||
 | 
					        self.bframe.pack(anchor="w")
 | 
				
			||||||
 | 
					        self.buttons = bl = []
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        self.bcont = b = Button(bframe, text="Go", command=self.cont)
 | 
				
			||||||
 | 
					        bl.append(b)
 | 
				
			||||||
 | 
					        self.bstep = b = Button(bframe, text="Step", command=self.step)
 | 
				
			||||||
 | 
					        bl.append(b)
 | 
				
			||||||
 | 
					        self.bnext = b = Button(bframe, text="Over", command=self.next)
 | 
				
			||||||
 | 
					        bl.append(b)
 | 
				
			||||||
 | 
					        self.bret = b = Button(bframe, text="Out", command=self.ret)
 | 
				
			||||||
 | 
					        bl.append(b)
 | 
				
			||||||
 | 
					        self.bret = b = Button(bframe, text="Quit", command=self.quit)
 | 
				
			||||||
 | 
					        bl.append(b)
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        for b in bl:
 | 
				
			||||||
 | 
					            b.configure(state="disabled")
 | 
				
			||||||
 | 
					            b.pack(side="left")
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        self.cframe = cframe = Frame(bframe)
 | 
				
			||||||
 | 
					        self.cframe.pack(side="left")
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        if not self.vstack:
 | 
				
			||||||
 | 
					            self.__class__.vstack = BooleanVar(top)
 | 
				
			||||||
 | 
					            self.vstack.set(1)
 | 
				
			||||||
 | 
					        self.bstack = Checkbutton(cframe,
 | 
				
			||||||
 | 
					            text="Stack", command=self.show_stack, variable=self.vstack)
 | 
				
			||||||
 | 
					        self.bstack.grid(row=0, column=0)
 | 
				
			||||||
 | 
					        if not self.vsource:
 | 
				
			||||||
 | 
					            self.__class__.vsource = BooleanVar(top)
 | 
				
			||||||
 | 
					            ##self.vsource.set(1)
 | 
				
			||||||
 | 
					        self.bsource = Checkbutton(cframe,
 | 
				
			||||||
 | 
					            text="Source", command=self.show_source, variable=self.vsource)
 | 
				
			||||||
 | 
					        self.bsource.grid(row=0, column=1)
 | 
				
			||||||
 | 
					        if not self.vlocals:
 | 
				
			||||||
 | 
					            self.__class__.vlocals = BooleanVar(top)
 | 
				
			||||||
 | 
					            self.vlocals.set(1)
 | 
				
			||||||
 | 
					        self.blocals = Checkbutton(cframe,
 | 
				
			||||||
 | 
					            text="Locals", command=self.show_locals, variable=self.vlocals)
 | 
				
			||||||
 | 
					        self.blocals.grid(row=1, column=0)
 | 
				
			||||||
 | 
					        if not self.vglobals:
 | 
				
			||||||
 | 
					            self.__class__.vglobals = BooleanVar(top)
 | 
				
			||||||
 | 
					            ##self.vglobals.set(1)
 | 
				
			||||||
 | 
					        self.bglobals = Checkbutton(cframe,
 | 
				
			||||||
 | 
					            text="Globals", command=self.show_globals, variable=self.vglobals)
 | 
				
			||||||
 | 
					        self.bglobals.grid(row=1, column=1)
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        self.status = Label(top, anchor="w")
 | 
				
			||||||
 | 
					        self.status.pack(anchor="w")
 | 
				
			||||||
 | 
					        self.error = Label(top, anchor="w")
 | 
				
			||||||
 | 
					        self.error.pack(anchor="w", fill="x")
 | 
				
			||||||
 | 
					        self.errorbg = self.error.cget("background")
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        self.fstack = Frame(top, height=1)
 | 
				
			||||||
 | 
					        self.fstack.pack(expand=1, fill="both")
 | 
				
			||||||
 | 
					        self.flocals = Frame(top)
 | 
				
			||||||
 | 
					        self.flocals.pack(expand=1, fill="both")
 | 
				
			||||||
 | 
					        self.fglobals = Frame(top, height=1)
 | 
				
			||||||
 | 
					        self.fglobals.pack(expand=1, fill="both")
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        if self.vstack.get():
 | 
				
			||||||
 | 
					            self.show_stack()
 | 
				
			||||||
 | 
					        if self.vlocals.get():
 | 
				
			||||||
 | 
					            self.show_locals()
 | 
				
			||||||
 | 
					        if self.vglobals.get():
 | 
				
			||||||
 | 
					            self.show_globals()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    frame = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def interaction(self, frame, info=None):
 | 
				
			||||||
 | 
					        self.frame = frame
 | 
				
			||||||
 | 
					        code = frame.f_code
 | 
				
			||||||
 | 
					        file = code.co_filename
 | 
				
			||||||
 | 
					        base = os.path.basename(file)
 | 
				
			||||||
 | 
					        lineno = frame.f_lineno
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        message = "%s:%s" % (base, lineno)
 | 
				
			||||||
 | 
					        if code.co_name != "?":
 | 
				
			||||||
 | 
					            message = "%s: %s()" % (message, code.co_name)
 | 
				
			||||||
 | 
					        self.status.configure(text=message)
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        if info:
 | 
				
			||||||
 | 
					            type, value, tb = info
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                m1 = type.__name__
 | 
				
			||||||
 | 
					            except AttributeError:
 | 
				
			||||||
 | 
					                m1 = "%s" % str(type)
 | 
				
			||||||
 | 
					            if value is not None:
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    m1 = "%s: %s" % (m1, str(value))
 | 
				
			||||||
 | 
					                except:
 | 
				
			||||||
 | 
					                    pass
 | 
				
			||||||
 | 
					            bg = "yellow"
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            m1 = ""
 | 
				
			||||||
 | 
					            tb = None
 | 
				
			||||||
 | 
					            bg = self.errorbg
 | 
				
			||||||
 | 
					        self.error.configure(text=m1, background=bg)
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        sv = self.stackviewer
 | 
				
			||||||
 | 
					        if sv:
 | 
				
			||||||
 | 
					            stack, i = self.get_stack(self.frame, tb)
 | 
				
			||||||
 | 
					            sv.load_stack(stack, i)
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        self.show_variables(1)
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        if self.vsource.get():
 | 
				
			||||||
 | 
					            self.sync_source_line()
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        for b in self.buttons:
 | 
				
			||||||
 | 
					            b.configure(state="normal")
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        self.top.tkraise()
 | 
				
			||||||
 | 
					        self.root.mainloop()
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        for b in self.buttons:
 | 
				
			||||||
 | 
					            b.configure(state="disabled")
 | 
				
			||||||
 | 
					        self.status.configure(text="")
 | 
				
			||||||
 | 
					        self.error.configure(text="", background=self.errorbg)
 | 
				
			||||||
 | 
					        self.frame = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def sync_source_line(self):
 | 
				
			||||||
 | 
					        frame = self.frame
 | 
				
			||||||
 | 
					        if not frame:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        code = frame.f_code
 | 
				
			||||||
 | 
					        file = code.co_filename
 | 
				
			||||||
 | 
					        lineno = frame.f_lineno
 | 
				
			||||||
 | 
					        if file[:1] + file[-1:] != "<>" and os.path.exists(file):
 | 
				
			||||||
 | 
					            edit = self.flist.open(file)
 | 
				
			||||||
 | 
					            if edit:
 | 
				
			||||||
 | 
					                edit.gotoline(lineno)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def cont(self):
 | 
				
			||||||
 | 
					        self.set_continue()
 | 
				
			||||||
 | 
					        self.root.quit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def step(self):
 | 
				
			||||||
 | 
					        self.set_step()
 | 
				
			||||||
 | 
					        self.root.quit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def next(self):
 | 
				
			||||||
 | 
					        self.set_next(self.frame)
 | 
				
			||||||
 | 
					        self.root.quit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ret(self):
 | 
				
			||||||
 | 
					        self.set_return(self.frame)
 | 
				
			||||||
 | 
					        self.root.quit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def quit(self):
 | 
				
			||||||
 | 
					        self.set_quit()
 | 
				
			||||||
 | 
					        self.root.quit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    stackviewer = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_stack(self):
 | 
				
			||||||
 | 
					        if not self.stackviewer and self.vstack.get():
 | 
				
			||||||
 | 
					            self.stackviewer = sv = StackViewer.StackViewer(
 | 
				
			||||||
 | 
					                self.fstack, self.flist, self)
 | 
				
			||||||
 | 
					            if self.frame:
 | 
				
			||||||
 | 
					                stack, i = self.get_stack(self.frame, None)
 | 
				
			||||||
 | 
					                sv.load_stack(stack, i)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            sv = self.stackviewer
 | 
				
			||||||
 | 
					            if sv and not self.vstack.get():
 | 
				
			||||||
 | 
					                self.stackviewer = None
 | 
				
			||||||
 | 
					                sv.close()
 | 
				
			||||||
 | 
					            self.fstack['height'] = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_source(self):
 | 
				
			||||||
 | 
					        if self.vsource.get():
 | 
				
			||||||
 | 
					            self.sync_source_line()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_frame(self, (frame, lineno)):
 | 
				
			||||||
 | 
					        self.frame = frame
 | 
				
			||||||
 | 
					        self.show_variables()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    localsviewer = None
 | 
				
			||||||
 | 
					    globalsviewer = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_locals(self):
 | 
				
			||||||
 | 
					        lv = self.localsviewer
 | 
				
			||||||
 | 
					        if self.vlocals.get():
 | 
				
			||||||
 | 
					            if not lv:
 | 
				
			||||||
 | 
					                self.localsviewer = StackViewer.NamespaceViewer(
 | 
				
			||||||
 | 
					                    self.flocals, "Locals")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if lv:
 | 
				
			||||||
 | 
					                self.localsviewer = None
 | 
				
			||||||
 | 
					                lv.close()
 | 
				
			||||||
 | 
					                self.flocals['height'] = 1
 | 
				
			||||||
 | 
					        self.show_variables()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_globals(self):
 | 
				
			||||||
 | 
					        gv = self.globalsviewer
 | 
				
			||||||
 | 
					        if self.vglobals.get():
 | 
				
			||||||
 | 
					            if not gv:
 | 
				
			||||||
 | 
					                self.globalsviewer = StackViewer.NamespaceViewer(
 | 
				
			||||||
 | 
					                    self.fglobals, "Globals")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if gv:
 | 
				
			||||||
 | 
					                self.globalsviewer = None
 | 
				
			||||||
 | 
					                gv.close()
 | 
				
			||||||
 | 
					                self.fglobals['height'] = 1
 | 
				
			||||||
 | 
					        self.show_variables()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_variables(self, force=0):
 | 
				
			||||||
 | 
					        lv = self.localsviewer
 | 
				
			||||||
 | 
					        gv = self.globalsviewer
 | 
				
			||||||
 | 
					        frame = self.frame
 | 
				
			||||||
 | 
					        if not frame:
 | 
				
			||||||
 | 
					            ldict = gdict = None
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            ldict = frame.f_locals
 | 
				
			||||||
 | 
					            gdict = frame.f_globals
 | 
				
			||||||
 | 
					            if lv and gv and ldict is gdict:
 | 
				
			||||||
 | 
					                ldict = None
 | 
				
			||||||
 | 
					        if lv:
 | 
				
			||||||
 | 
					            lv.load_dict(ldict, force)
 | 
				
			||||||
 | 
					        if gv:
 | 
				
			||||||
 | 
					            gv.load_dict(gdict, force)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_breakpoint_here(self, edit):
 | 
				
			||||||
 | 
					        text = edit.text
 | 
				
			||||||
 | 
					        filename = edit.io.filename
 | 
				
			||||||
 | 
					        if not filename:
 | 
				
			||||||
 | 
					            text.bell()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        lineno = int(float(text.index("insert")))
 | 
				
			||||||
 | 
					        msg = self.set_break(filename, lineno)
 | 
				
			||||||
 | 
					        if msg:
 | 
				
			||||||
 | 
					            text.bell()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        text.tag_add("BREAK", "insert linestart", "insert lineend +1char")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # A literal copy of Bdb.set_break() without the print statement at the end
 | 
				
			||||||
 | 
					    def set_break(self, filename, lineno, temporary=0, cond = None):
 | 
				
			||||||
 | 
					        import linecache # Import as late as possible
 | 
				
			||||||
 | 
					        line = linecache.getline(filename, lineno)
 | 
				
			||||||
 | 
					        if not line:
 | 
				
			||||||
 | 
					                return 'That line does not exist!'
 | 
				
			||||||
 | 
					        if not self.breaks.has_key(filename):
 | 
				
			||||||
 | 
					                self.breaks[filename] = []
 | 
				
			||||||
 | 
					        list = self.breaks[filename]
 | 
				
			||||||
 | 
					        if not lineno in list:
 | 
				
			||||||
 | 
					                list.append(lineno)
 | 
				
			||||||
 | 
					        bp = bdb.Breakpoint(filename, lineno, temporary, cond)
 | 
				
			||||||
							
								
								
									
										34
									
								
								Lib/idlelib/Delegator.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								Lib/idlelib/Delegator.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,34 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Delegator:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # The cache is only used to be able to change delegates!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, delegate=None):
 | 
				
			||||||
 | 
					        self.delegate = delegate
 | 
				
			||||||
 | 
					        self.__cache = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __getattr__(self, name):
 | 
				
			||||||
 | 
					        attr = getattr(self.delegate, name) # May raise AttributeError
 | 
				
			||||||
 | 
					        setattr(self, name, attr)
 | 
				
			||||||
 | 
					        self.__cache[name] = attr
 | 
				
			||||||
 | 
					        return attr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def resetcache(self):
 | 
				
			||||||
 | 
					        for key in self.__cache.keys():
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                delattr(self, key)
 | 
				
			||||||
 | 
					            except AttributeError:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					        self.__cache.clear()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def cachereport(self):
 | 
				
			||||||
 | 
					        keys = self.__cache.keys()
 | 
				
			||||||
 | 
					        keys.sort()
 | 
				
			||||||
 | 
					        print keys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setdelegate(self, delegate):
 | 
				
			||||||
 | 
					        self.resetcache()
 | 
				
			||||||
 | 
					        self.delegate = delegate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getdelegate(self):
 | 
				
			||||||
 | 
					        return self.delegate
 | 
				
			||||||
							
								
								
									
										749
									
								
								Lib/idlelib/EditorWindow.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										749
									
								
								Lib/idlelib/EditorWindow.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,749 @@
 | 
				
			||||||
 | 
					# changes by dscherer@cmu.edu
 | 
				
			||||||
 | 
					#   - created format and run menus
 | 
				
			||||||
 | 
					#   - added silly advice dialog (apologies to Douglas Adams)
 | 
				
			||||||
 | 
					#   - made Python Documentation work on Windows (requires win32api to
 | 
				
			||||||
 | 
					#     do a ShellExecute(); other ways of starting a web browser are awkward)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import imp
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					import tkSimpleDialog
 | 
				
			||||||
 | 
					import tkMessageBox
 | 
				
			||||||
 | 
					import idlever
 | 
				
			||||||
 | 
					import WindowList
 | 
				
			||||||
 | 
					from IdleConf import idleconf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The default tab setting for a Text widget, in average-width characters.
 | 
				
			||||||
 | 
					TK_TABWIDTH_DEFAULT = 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# File menu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<open-module>>
 | 
				
			||||||
 | 
					#$ win <Alt-m>
 | 
				
			||||||
 | 
					#$ unix <Control-x><Control-m>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<open-class-browser>>
 | 
				
			||||||
 | 
					#$ win <Alt-c>
 | 
				
			||||||
 | 
					#$ unix <Control-x><Control-b>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<open-path-browser>>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<close-window>>
 | 
				
			||||||
 | 
					#$ unix <Control-x><Control-0>
 | 
				
			||||||
 | 
					#$ unix <Control-x><Key-0>
 | 
				
			||||||
 | 
					#$ win <Alt-F4>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Edit menu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<Copy>>
 | 
				
			||||||
 | 
					#$ win <Control-c>
 | 
				
			||||||
 | 
					#$ unix <Alt-w>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<Cut>>
 | 
				
			||||||
 | 
					#$ win <Control-x>
 | 
				
			||||||
 | 
					#$ unix <Control-w>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<Paste>>
 | 
				
			||||||
 | 
					#$ win <Control-v>
 | 
				
			||||||
 | 
					#$ unix <Control-y>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<select-all>>
 | 
				
			||||||
 | 
					#$ win <Alt-a>
 | 
				
			||||||
 | 
					#$ unix <Alt-a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Help menu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<help>>
 | 
				
			||||||
 | 
					#$ win <F1>
 | 
				
			||||||
 | 
					#$ unix <F1>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<about-idle>>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Events without menu entries
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<remove-selection>>
 | 
				
			||||||
 | 
					#$ win <Escape>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<center-insert>>
 | 
				
			||||||
 | 
					#$ win <Control-l>
 | 
				
			||||||
 | 
					#$ unix <Control-l>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<do-nothing>>
 | 
				
			||||||
 | 
					#$ unix <Control-x>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					about_title = "About IDLE"
 | 
				
			||||||
 | 
					about_text = """\
 | 
				
			||||||
 | 
					IDLE %s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					An Integrated DeveLopment Environment for Python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					by Guido van Rossum
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This version of IDLE has been modified by David Scherer
 | 
				
			||||||
 | 
					  (dscherer@cmu.edu).  See readme.txt for details.
 | 
				
			||||||
 | 
					""" % idlever.IDLE_VERSION
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class EditorWindow:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    from Percolator import Percolator
 | 
				
			||||||
 | 
					    from ColorDelegator import ColorDelegator
 | 
				
			||||||
 | 
					    from UndoDelegator import UndoDelegator
 | 
				
			||||||
 | 
					    from IOBinding import IOBinding
 | 
				
			||||||
 | 
					    import Bindings
 | 
				
			||||||
 | 
					    from Tkinter import Toplevel
 | 
				
			||||||
 | 
					    from MultiStatusBar import MultiStatusBar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    about_title = about_title
 | 
				
			||||||
 | 
					    about_text = about_text
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    vars = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, flist=None, filename=None, key=None, root=None):
 | 
				
			||||||
 | 
					        edconf = idleconf.getsection('EditorWindow')
 | 
				
			||||||
 | 
					        coconf = idleconf.getsection('Colors')
 | 
				
			||||||
 | 
					        self.flist = flist
 | 
				
			||||||
 | 
					        root = root or flist.root
 | 
				
			||||||
 | 
					        self.root = root
 | 
				
			||||||
 | 
					        if flist:
 | 
				
			||||||
 | 
					            self.vars = flist.vars
 | 
				
			||||||
 | 
					        self.menubar = Menu(root)
 | 
				
			||||||
 | 
					        self.top = top = self.Toplevel(root, menu=self.menubar)
 | 
				
			||||||
 | 
					        self.vbar = vbar = Scrollbar(top, name='vbar')
 | 
				
			||||||
 | 
					        self.text_frame = text_frame = Frame(top)
 | 
				
			||||||
 | 
					        self.text = text = Text(text_frame, name='text', padx=5,
 | 
				
			||||||
 | 
					                      foreground=coconf.getdef('normal-foreground'),
 | 
				
			||||||
 | 
					                      background=coconf.getdef('normal-background'),
 | 
				
			||||||
 | 
					                      highlightcolor=coconf.getdef('hilite-foreground'),
 | 
				
			||||||
 | 
					                      highlightbackground=coconf.getdef('hilite-background'),
 | 
				
			||||||
 | 
					                      insertbackground=coconf.getdef('cursor-background'),
 | 
				
			||||||
 | 
					                      width=edconf.getint('width'),
 | 
				
			||||||
 | 
					                      height=edconf.getint('height'),
 | 
				
			||||||
 | 
					                      wrap="none")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.createmenubar()
 | 
				
			||||||
 | 
					        self.apply_bindings()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.top.protocol("WM_DELETE_WINDOW", self.close)
 | 
				
			||||||
 | 
					        self.top.bind("<<close-window>>", self.close_event)
 | 
				
			||||||
 | 
					        text.bind("<<center-insert>>", self.center_insert_event)
 | 
				
			||||||
 | 
					        text.bind("<<help>>", self.help_dialog)
 | 
				
			||||||
 | 
					        text.bind("<<good-advice>>", self.good_advice)
 | 
				
			||||||
 | 
					        text.bind("<<python-docs>>", self.python_docs)
 | 
				
			||||||
 | 
					        text.bind("<<about-idle>>", self.about_dialog)
 | 
				
			||||||
 | 
					        text.bind("<<open-module>>", self.open_module)
 | 
				
			||||||
 | 
					        text.bind("<<do-nothing>>", lambda event: "break")
 | 
				
			||||||
 | 
					        text.bind("<<select-all>>", self.select_all)
 | 
				
			||||||
 | 
					        text.bind("<<remove-selection>>", self.remove_selection)
 | 
				
			||||||
 | 
					        text.bind("<3>", self.right_menu_event)
 | 
				
			||||||
 | 
					        if flist:
 | 
				
			||||||
 | 
					            flist.inversedict[self] = key
 | 
				
			||||||
 | 
					            if key:
 | 
				
			||||||
 | 
					                flist.dict[key] = self
 | 
				
			||||||
 | 
					            text.bind("<<open-new-window>>", self.flist.new_callback)
 | 
				
			||||||
 | 
					            text.bind("<<close-all-windows>>", self.flist.close_all_callback)
 | 
				
			||||||
 | 
					            text.bind("<<open-class-browser>>", self.open_class_browser)
 | 
				
			||||||
 | 
					            text.bind("<<open-path-browser>>", self.open_path_browser)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        vbar['command'] = text.yview
 | 
				
			||||||
 | 
					        vbar.pack(side=RIGHT, fill=Y)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        text['yscrollcommand'] = vbar.set
 | 
				
			||||||
 | 
					        text['font'] = edconf.get('font-name'), edconf.get('font-size')
 | 
				
			||||||
 | 
					        text_frame.pack(side=LEFT, fill=BOTH, expand=1)
 | 
				
			||||||
 | 
					        text.pack(side=TOP, fill=BOTH, expand=1)
 | 
				
			||||||
 | 
					        text.focus_set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.per = per = self.Percolator(text)
 | 
				
			||||||
 | 
					        if self.ispythonsource(filename):
 | 
				
			||||||
 | 
					            self.color = color = self.ColorDelegator(); per.insertfilter(color)
 | 
				
			||||||
 | 
					            ##print "Initial colorizer"
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            ##print "No initial colorizer"
 | 
				
			||||||
 | 
					            self.color = None
 | 
				
			||||||
 | 
					        self.undo = undo = self.UndoDelegator(); per.insertfilter(undo)
 | 
				
			||||||
 | 
					        self.io = io = self.IOBinding(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        text.undo_block_start = undo.undo_block_start
 | 
				
			||||||
 | 
					        text.undo_block_stop = undo.undo_block_stop
 | 
				
			||||||
 | 
					        undo.set_saved_change_hook(self.saved_change_hook)
 | 
				
			||||||
 | 
					        io.set_filename_change_hook(self.filename_change_hook)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if filename:
 | 
				
			||||||
 | 
					            if os.path.exists(filename):
 | 
				
			||||||
 | 
					                io.loadfile(filename)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                io.set_filename(filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.saved_change_hook()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.load_extensions()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        menu = self.menudict.get('windows')
 | 
				
			||||||
 | 
					        if menu:
 | 
				
			||||||
 | 
					            end = menu.index("end")
 | 
				
			||||||
 | 
					            if end is None:
 | 
				
			||||||
 | 
					                end = -1
 | 
				
			||||||
 | 
					            if end >= 0:
 | 
				
			||||||
 | 
					                menu.add_separator()
 | 
				
			||||||
 | 
					                end = end + 1
 | 
				
			||||||
 | 
					            self.wmenu_end = end
 | 
				
			||||||
 | 
					            WindowList.register_callback(self.postwindowsmenu)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Some abstractions so IDLE extensions are cross-IDE
 | 
				
			||||||
 | 
					        self.askyesno = tkMessageBox.askyesno
 | 
				
			||||||
 | 
					        self.askinteger = tkSimpleDialog.askinteger
 | 
				
			||||||
 | 
					        self.showerror = tkMessageBox.showerror
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.extensions.has_key('AutoIndent'):
 | 
				
			||||||
 | 
					            self.extensions['AutoIndent'].set_indentation_params(
 | 
				
			||||||
 | 
					                self.ispythonsource(filename))
 | 
				
			||||||
 | 
					        self.set_status_bar()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_status_bar(self):
 | 
				
			||||||
 | 
					        self.status_bar = self.MultiStatusBar(self.text_frame)
 | 
				
			||||||
 | 
					        self.status_bar.set_label('column', 'Col: ?', side=RIGHT)
 | 
				
			||||||
 | 
					        self.status_bar.set_label('line', 'Ln: ?', side=RIGHT)
 | 
				
			||||||
 | 
					        self.status_bar.pack(side=BOTTOM, fill=X)
 | 
				
			||||||
 | 
					        self.text.bind('<KeyRelease>', self.set_line_and_column)
 | 
				
			||||||
 | 
					        self.text.bind('<ButtonRelease>', self.set_line_and_column)
 | 
				
			||||||
 | 
					        self.text.after_idle(self.set_line_and_column)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_line_and_column(self, event=None):
 | 
				
			||||||
 | 
					        line, column = string.split(self.text.index(INSERT), '.')
 | 
				
			||||||
 | 
					        self.status_bar.set_label('column', 'Col: %s' % column)
 | 
				
			||||||
 | 
					        self.status_bar.set_label('line', 'Ln: %s' % line)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def wakeup(self):
 | 
				
			||||||
 | 
					        if self.top.wm_state() == "iconic":
 | 
				
			||||||
 | 
					            self.top.wm_deiconify()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.top.tkraise()
 | 
				
			||||||
 | 
					        self.text.focus_set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    menu_specs = [
 | 
				
			||||||
 | 
					        ("file", "_File"),
 | 
				
			||||||
 | 
					        ("edit", "_Edit"),
 | 
				
			||||||
 | 
					        ("format", "F_ormat"),
 | 
				
			||||||
 | 
					        ("run", "_Run"),
 | 
				
			||||||
 | 
					        ("windows", "_Windows"),
 | 
				
			||||||
 | 
					        ("help", "_Help"),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def createmenubar(self):
 | 
				
			||||||
 | 
					        mbar = self.menubar
 | 
				
			||||||
 | 
					        self.menudict = menudict = {}
 | 
				
			||||||
 | 
					        for name, label in self.menu_specs:
 | 
				
			||||||
 | 
					            underline, label = prepstr(label)
 | 
				
			||||||
 | 
					            menudict[name] = menu = Menu(mbar, name=name)
 | 
				
			||||||
 | 
					            mbar.add_cascade(label=label, menu=menu, underline=underline)
 | 
				
			||||||
 | 
					        self.fill_menus()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def postwindowsmenu(self):
 | 
				
			||||||
 | 
					        # Only called when Windows menu exists
 | 
				
			||||||
 | 
					        # XXX Actually, this Just-In-Time updating interferes badly
 | 
				
			||||||
 | 
					        # XXX with the tear-off feature.  It would be better to update
 | 
				
			||||||
 | 
					        # XXX all Windows menus whenever the list of windows changes.
 | 
				
			||||||
 | 
					        menu = self.menudict['windows']
 | 
				
			||||||
 | 
					        end = menu.index("end")
 | 
				
			||||||
 | 
					        if end is None:
 | 
				
			||||||
 | 
					            end = -1
 | 
				
			||||||
 | 
					        if end > self.wmenu_end:
 | 
				
			||||||
 | 
					            menu.delete(self.wmenu_end+1, end)
 | 
				
			||||||
 | 
					        WindowList.add_windows_to_menu(menu)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rmenu = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def right_menu_event(self, event):
 | 
				
			||||||
 | 
					        self.text.tag_remove("sel", "1.0", "end")
 | 
				
			||||||
 | 
					        self.text.mark_set("insert", "@%d,%d" % (event.x, event.y))
 | 
				
			||||||
 | 
					        if not self.rmenu:
 | 
				
			||||||
 | 
					            self.make_rmenu()
 | 
				
			||||||
 | 
					        rmenu = self.rmenu
 | 
				
			||||||
 | 
					        self.event = event
 | 
				
			||||||
 | 
					        iswin = sys.platform[:3] == 'win'
 | 
				
			||||||
 | 
					        if iswin:
 | 
				
			||||||
 | 
					            self.text.config(cursor="arrow")
 | 
				
			||||||
 | 
					        rmenu.tk_popup(event.x_root, event.y_root)
 | 
				
			||||||
 | 
					        if iswin:
 | 
				
			||||||
 | 
					            self.text.config(cursor="ibeam")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rmenu_specs = [
 | 
				
			||||||
 | 
					        # ("Label", "<<virtual-event>>"), ...
 | 
				
			||||||
 | 
					        ("Close", "<<close-window>>"), # Example
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def make_rmenu(self):
 | 
				
			||||||
 | 
					        rmenu = Menu(self.text, tearoff=0)
 | 
				
			||||||
 | 
					        for label, eventname in self.rmenu_specs:
 | 
				
			||||||
 | 
					            def command(text=self.text, eventname=eventname):
 | 
				
			||||||
 | 
					                text.event_generate(eventname)
 | 
				
			||||||
 | 
					            rmenu.add_command(label=label, command=command)
 | 
				
			||||||
 | 
					        self.rmenu = rmenu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def about_dialog(self, event=None):
 | 
				
			||||||
 | 
					        tkMessageBox.showinfo(self.about_title, self.about_text,
 | 
				
			||||||
 | 
					                              master=self.text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    helpfile = "help.txt"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def good_advice(self, event=None):
 | 
				
			||||||
 | 
					        tkMessageBox.showinfo('Advice', "Don't Panic!", master=self.text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def help_dialog(self, event=None):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            helpfile = os.path.join(os.path.dirname(__file__), self.helpfile)
 | 
				
			||||||
 | 
					        except NameError:
 | 
				
			||||||
 | 
					            helpfile = self.helpfile
 | 
				
			||||||
 | 
					        if self.flist:
 | 
				
			||||||
 | 
					            self.flist.open(helpfile)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.io.loadfile(helpfile)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    help_viewer = "netscape -remote 'openurl(%(url)s)' 2>/dev/null || " \
 | 
				
			||||||
 | 
					                  "netscape %(url)s &"
 | 
				
			||||||
 | 
					    help_url = "http://www.python.org/doc/current/"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def python_docs(self, event=None):
 | 
				
			||||||
 | 
					        if sys.platform=='win32':
 | 
				
			||||||
 | 
					          try:
 | 
				
			||||||
 | 
					            import win32api
 | 
				
			||||||
 | 
					            import ExecBinding
 | 
				
			||||||
 | 
					            doc = os.path.join( os.path.dirname( ExecBinding.pyth_exe ), "doc", "index.html" )
 | 
				
			||||||
 | 
					            win32api.ShellExecute(0, None, doc, None, sys.path[0], 1)
 | 
				
			||||||
 | 
					          except:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					          cmd = self.help_viewer % {"url": self.help_url}
 | 
				
			||||||
 | 
					          os.system(cmd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def select_all(self, event=None):
 | 
				
			||||||
 | 
					        self.text.tag_add("sel", "1.0", "end-1c")
 | 
				
			||||||
 | 
					        self.text.mark_set("insert", "1.0")
 | 
				
			||||||
 | 
					        self.text.see("insert")
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def remove_selection(self, event=None):
 | 
				
			||||||
 | 
					        self.text.tag_remove("sel", "1.0", "end")
 | 
				
			||||||
 | 
					        self.text.see("insert")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def open_module(self, event=None):
 | 
				
			||||||
 | 
					        # XXX Shouldn't this be in IOBinding or in FileList?
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            name = self.text.get("sel.first", "sel.last")
 | 
				
			||||||
 | 
					        except TclError:
 | 
				
			||||||
 | 
					            name = ""
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            name = string.strip(name)
 | 
				
			||||||
 | 
					        if not name:
 | 
				
			||||||
 | 
					            name = tkSimpleDialog.askstring("Module",
 | 
				
			||||||
 | 
					                     "Enter the name of a Python module\n"
 | 
				
			||||||
 | 
					                     "to search on sys.path and open:",
 | 
				
			||||||
 | 
					                     parent=self.text)
 | 
				
			||||||
 | 
					            if name:
 | 
				
			||||||
 | 
					                name = string.strip(name)
 | 
				
			||||||
 | 
					            if not name:
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					        # XXX Ought to support package syntax
 | 
				
			||||||
 | 
					        # XXX Ought to insert current file's directory in front of path
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            (f, file, (suffix, mode, type)) = imp.find_module(name)
 | 
				
			||||||
 | 
					        except (NameError, ImportError), msg:
 | 
				
			||||||
 | 
					            tkMessageBox.showerror("Import error", str(msg), parent=self.text)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if type != imp.PY_SOURCE:
 | 
				
			||||||
 | 
					            tkMessageBox.showerror("Unsupported type",
 | 
				
			||||||
 | 
					                "%s is not a source module" % name, parent=self.text)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if f:
 | 
				
			||||||
 | 
					            f.close()
 | 
				
			||||||
 | 
					        if self.flist:
 | 
				
			||||||
 | 
					            self.flist.open(file)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.io.loadfile(file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def open_class_browser(self, event=None):
 | 
				
			||||||
 | 
					        filename = self.io.filename
 | 
				
			||||||
 | 
					        if not filename:
 | 
				
			||||||
 | 
					            tkMessageBox.showerror(
 | 
				
			||||||
 | 
					                "No filename",
 | 
				
			||||||
 | 
					                "This buffer has no associated filename",
 | 
				
			||||||
 | 
					                master=self.text)
 | 
				
			||||||
 | 
					            self.text.focus_set()
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        head, tail = os.path.split(filename)
 | 
				
			||||||
 | 
					        base, ext = os.path.splitext(tail)
 | 
				
			||||||
 | 
					        import ClassBrowser
 | 
				
			||||||
 | 
					        ClassBrowser.ClassBrowser(self.flist, base, [head])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def open_path_browser(self, event=None):
 | 
				
			||||||
 | 
					        import PathBrowser
 | 
				
			||||||
 | 
					        PathBrowser.PathBrowser(self.flist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def gotoline(self, lineno):
 | 
				
			||||||
 | 
					        if lineno is not None and lineno > 0:
 | 
				
			||||||
 | 
					            self.text.mark_set("insert", "%d.0" % lineno)
 | 
				
			||||||
 | 
					            self.text.tag_remove("sel", "1.0", "end")
 | 
				
			||||||
 | 
					            self.text.tag_add("sel", "insert", "insert +1l")
 | 
				
			||||||
 | 
					            self.center()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ispythonsource(self, filename):
 | 
				
			||||||
 | 
					        if not filename:
 | 
				
			||||||
 | 
					            return 1
 | 
				
			||||||
 | 
					        base, ext = os.path.splitext(os.path.basename(filename))
 | 
				
			||||||
 | 
					        if os.path.normcase(ext) in (".py", ".pyw"):
 | 
				
			||||||
 | 
					            return 1
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            f = open(filename)
 | 
				
			||||||
 | 
					            line = f.readline()
 | 
				
			||||||
 | 
					            f.close()
 | 
				
			||||||
 | 
					        except IOError:
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        return line[:2] == '#!' and string.find(line, 'python') >= 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close_hook(self):
 | 
				
			||||||
 | 
					        if self.flist:
 | 
				
			||||||
 | 
					            self.flist.close_edit(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_close_hook(self, close_hook):
 | 
				
			||||||
 | 
					        self.close_hook = close_hook
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def filename_change_hook(self):
 | 
				
			||||||
 | 
					        if self.flist:
 | 
				
			||||||
 | 
					            self.flist.filename_changed_edit(self)
 | 
				
			||||||
 | 
					        self.saved_change_hook()
 | 
				
			||||||
 | 
					        if self.ispythonsource(self.io.filename):
 | 
				
			||||||
 | 
					            self.addcolorizer()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.rmcolorizer()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def addcolorizer(self):
 | 
				
			||||||
 | 
					        if self.color:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        ##print "Add colorizer"
 | 
				
			||||||
 | 
					        self.per.removefilter(self.undo)
 | 
				
			||||||
 | 
					        self.color = self.ColorDelegator()
 | 
				
			||||||
 | 
					        self.per.insertfilter(self.color)
 | 
				
			||||||
 | 
					        self.per.insertfilter(self.undo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def rmcolorizer(self):
 | 
				
			||||||
 | 
					        if not self.color:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        ##print "Remove colorizer"
 | 
				
			||||||
 | 
					        self.per.removefilter(self.undo)
 | 
				
			||||||
 | 
					        self.per.removefilter(self.color)
 | 
				
			||||||
 | 
					        self.color = None
 | 
				
			||||||
 | 
					        self.per.insertfilter(self.undo)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def saved_change_hook(self):
 | 
				
			||||||
 | 
					        short = self.short_title()
 | 
				
			||||||
 | 
					        long = self.long_title()
 | 
				
			||||||
 | 
					        if short and long:
 | 
				
			||||||
 | 
					            title = short + " - " + long
 | 
				
			||||||
 | 
					        elif short:
 | 
				
			||||||
 | 
					            title = short
 | 
				
			||||||
 | 
					        elif long:
 | 
				
			||||||
 | 
					            title = long
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            title = "Untitled"
 | 
				
			||||||
 | 
					        icon = short or long or title
 | 
				
			||||||
 | 
					        if not self.get_saved():
 | 
				
			||||||
 | 
					            title = "*%s*" % title
 | 
				
			||||||
 | 
					            icon = "*%s" % icon
 | 
				
			||||||
 | 
					        self.top.wm_title(title)
 | 
				
			||||||
 | 
					        self.top.wm_iconname(icon)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_saved(self):
 | 
				
			||||||
 | 
					        return self.undo.get_saved()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_saved(self, flag):
 | 
				
			||||||
 | 
					        self.undo.set_saved(flag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def reset_undo(self):
 | 
				
			||||||
 | 
					        self.undo.reset_undo()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def short_title(self):
 | 
				
			||||||
 | 
					        filename = self.io.filename
 | 
				
			||||||
 | 
					        if filename:
 | 
				
			||||||
 | 
					            filename = os.path.basename(filename)
 | 
				
			||||||
 | 
					        return filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def long_title(self):
 | 
				
			||||||
 | 
					        return self.io.filename or ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def center_insert_event(self, event):
 | 
				
			||||||
 | 
					        self.center()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def center(self, mark="insert"):
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        top, bot = self.getwindowlines()
 | 
				
			||||||
 | 
					        lineno = self.getlineno(mark)
 | 
				
			||||||
 | 
					        height = bot - top
 | 
				
			||||||
 | 
					        newtop = max(1, lineno - height/2)
 | 
				
			||||||
 | 
					        text.yview(float(newtop))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getwindowlines(self):
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        top = self.getlineno("@0,0")
 | 
				
			||||||
 | 
					        bot = self.getlineno("@0,65535")
 | 
				
			||||||
 | 
					        if top == bot and text.winfo_height() == 1:
 | 
				
			||||||
 | 
					            # Geometry manager hasn't run yet
 | 
				
			||||||
 | 
					            height = int(text['height'])
 | 
				
			||||||
 | 
					            bot = top + height - 1
 | 
				
			||||||
 | 
					        return top, bot
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getlineno(self, mark="insert"):
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        return int(float(text.index(mark)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close_event(self, event):
 | 
				
			||||||
 | 
					        self.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def maybesave(self):
 | 
				
			||||||
 | 
					        if self.io:
 | 
				
			||||||
 | 
					            return self.io.maybesave()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self):
 | 
				
			||||||
 | 
					        self.top.wm_deiconify()
 | 
				
			||||||
 | 
					        self.top.tkraise()
 | 
				
			||||||
 | 
					        reply = self.maybesave()
 | 
				
			||||||
 | 
					        if reply != "cancel":
 | 
				
			||||||
 | 
					            self._close()
 | 
				
			||||||
 | 
					        return reply
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _close(self):
 | 
				
			||||||
 | 
					        WindowList.unregister_callback(self.postwindowsmenu)
 | 
				
			||||||
 | 
					        if self.close_hook:
 | 
				
			||||||
 | 
					            self.close_hook()
 | 
				
			||||||
 | 
					        self.flist = None
 | 
				
			||||||
 | 
					        colorizing = 0
 | 
				
			||||||
 | 
					        self.unload_extensions()
 | 
				
			||||||
 | 
					        self.io.close(); self.io = None
 | 
				
			||||||
 | 
					        self.undo = None # XXX
 | 
				
			||||||
 | 
					        if self.color:
 | 
				
			||||||
 | 
					            colorizing = self.color.colorizing
 | 
				
			||||||
 | 
					            doh = colorizing and self.top
 | 
				
			||||||
 | 
					            self.color.close(doh) # Cancel colorization
 | 
				
			||||||
 | 
					        self.text = None
 | 
				
			||||||
 | 
					        self.vars = None
 | 
				
			||||||
 | 
					        self.per.close(); self.per = None
 | 
				
			||||||
 | 
					        if not colorizing:
 | 
				
			||||||
 | 
					            self.top.destroy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def load_extensions(self):
 | 
				
			||||||
 | 
					        self.extensions = {}
 | 
				
			||||||
 | 
					        self.load_standard_extensions()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def unload_extensions(self):
 | 
				
			||||||
 | 
					        for ins in self.extensions.values():
 | 
				
			||||||
 | 
					            if hasattr(ins, "close"):
 | 
				
			||||||
 | 
					                ins.close()
 | 
				
			||||||
 | 
					        self.extensions = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def load_standard_extensions(self):
 | 
				
			||||||
 | 
					        for name in self.get_standard_extension_names():
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                self.load_extension(name)
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                print "Failed to load extension", `name`
 | 
				
			||||||
 | 
					                import traceback
 | 
				
			||||||
 | 
					                traceback.print_exc()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_standard_extension_names(self):
 | 
				
			||||||
 | 
					        return idleconf.getextensions()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def load_extension(self, name):
 | 
				
			||||||
 | 
					        mod = __import__(name, globals(), locals(), [])
 | 
				
			||||||
 | 
					        cls = getattr(mod, name)
 | 
				
			||||||
 | 
					        ins = cls(self)
 | 
				
			||||||
 | 
					        self.extensions[name] = ins
 | 
				
			||||||
 | 
					        kdnames = ["keydefs"]
 | 
				
			||||||
 | 
					        if sys.platform == 'win32':
 | 
				
			||||||
 | 
					            kdnames.append("windows_keydefs")
 | 
				
			||||||
 | 
					        elif sys.platform == 'mac':
 | 
				
			||||||
 | 
					            kdnames.append("mac_keydefs")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            kdnames.append("unix_keydefs")
 | 
				
			||||||
 | 
					        keydefs = {}
 | 
				
			||||||
 | 
					        for kdname in kdnames:
 | 
				
			||||||
 | 
					            if hasattr(ins, kdname):
 | 
				
			||||||
 | 
					                keydefs.update(getattr(ins, kdname))
 | 
				
			||||||
 | 
					        if keydefs:
 | 
				
			||||||
 | 
					            self.apply_bindings(keydefs)
 | 
				
			||||||
 | 
					            for vevent in keydefs.keys():
 | 
				
			||||||
 | 
					                methodname = string.replace(vevent, "-", "_")
 | 
				
			||||||
 | 
					                while methodname[:1] == '<':
 | 
				
			||||||
 | 
					                    methodname = methodname[1:]
 | 
				
			||||||
 | 
					                while methodname[-1:] == '>':
 | 
				
			||||||
 | 
					                    methodname = methodname[:-1]
 | 
				
			||||||
 | 
					                methodname = methodname + "_event"
 | 
				
			||||||
 | 
					                if hasattr(ins, methodname):
 | 
				
			||||||
 | 
					                    self.text.bind(vevent, getattr(ins, methodname))
 | 
				
			||||||
 | 
					        if hasattr(ins, "menudefs"):
 | 
				
			||||||
 | 
					            self.fill_menus(ins.menudefs, keydefs)
 | 
				
			||||||
 | 
					        return ins
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def apply_bindings(self, keydefs=None):
 | 
				
			||||||
 | 
					        if keydefs is None:
 | 
				
			||||||
 | 
					            keydefs = self.Bindings.default_keydefs
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        text.keydefs = keydefs
 | 
				
			||||||
 | 
					        for event, keylist in keydefs.items():
 | 
				
			||||||
 | 
					            if keylist:
 | 
				
			||||||
 | 
					                apply(text.event_add, (event,) + tuple(keylist))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def fill_menus(self, defs=None, keydefs=None):
 | 
				
			||||||
 | 
					        # Fill the menus. Menus that are absent or None in
 | 
				
			||||||
 | 
					        # self.menudict are ignored.
 | 
				
			||||||
 | 
					        if defs is None:
 | 
				
			||||||
 | 
					            defs = self.Bindings.menudefs
 | 
				
			||||||
 | 
					        if keydefs is None:
 | 
				
			||||||
 | 
					            keydefs = self.Bindings.default_keydefs
 | 
				
			||||||
 | 
					        menudict = self.menudict
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        for mname, itemlist in defs:
 | 
				
			||||||
 | 
					            menu = menudict.get(mname)
 | 
				
			||||||
 | 
					            if not menu:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            for item in itemlist:
 | 
				
			||||||
 | 
					                if not item:
 | 
				
			||||||
 | 
					                    menu.add_separator()
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    label, event = item
 | 
				
			||||||
 | 
					                    checkbutton = (label[:1] == '!')
 | 
				
			||||||
 | 
					                    if checkbutton:
 | 
				
			||||||
 | 
					                        label = label[1:]
 | 
				
			||||||
 | 
					                    underline, label = prepstr(label)
 | 
				
			||||||
 | 
					                    accelerator = get_accelerator(keydefs, event)
 | 
				
			||||||
 | 
					                    def command(text=text, event=event):
 | 
				
			||||||
 | 
					                        text.event_generate(event)
 | 
				
			||||||
 | 
					                    if checkbutton:
 | 
				
			||||||
 | 
					                        var = self.getrawvar(event, BooleanVar)
 | 
				
			||||||
 | 
					                        menu.add_checkbutton(label=label, underline=underline,
 | 
				
			||||||
 | 
					                            command=command, accelerator=accelerator,
 | 
				
			||||||
 | 
					                            variable=var)
 | 
				
			||||||
 | 
					                    else:
 | 
				
			||||||
 | 
					                        menu.add_command(label=label, underline=underline,
 | 
				
			||||||
 | 
					                            command=command, accelerator=accelerator)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getvar(self, name):
 | 
				
			||||||
 | 
					        var = self.getrawvar(name)
 | 
				
			||||||
 | 
					        if var:
 | 
				
			||||||
 | 
					            return var.get()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setvar(self, name, value, vartype=None):
 | 
				
			||||||
 | 
					        var = self.getrawvar(name, vartype)
 | 
				
			||||||
 | 
					        if var:
 | 
				
			||||||
 | 
					            var.set(value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getrawvar(self, name, vartype=None):
 | 
				
			||||||
 | 
					        var = self.vars.get(name)
 | 
				
			||||||
 | 
					        if not var and vartype:
 | 
				
			||||||
 | 
					            self.vars[name] = var = vartype(self.text)
 | 
				
			||||||
 | 
					        return var
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Tk implementations of "virtual text methods" -- each platform
 | 
				
			||||||
 | 
					    # reusing IDLE's support code needs to define these for its GUI's
 | 
				
			||||||
 | 
					    # flavor of widget.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Is character at text_index in a Python string?  Return 0 for
 | 
				
			||||||
 | 
					    # "guaranteed no", true for anything else.  This info is expensive
 | 
				
			||||||
 | 
					    # to compute ab initio, but is probably already known by the
 | 
				
			||||||
 | 
					    # platform's colorizer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def is_char_in_string(self, text_index):
 | 
				
			||||||
 | 
					        if self.color:
 | 
				
			||||||
 | 
					            # Return true iff colorizer hasn't (re)gotten this far
 | 
				
			||||||
 | 
					            # yet, or the character is tagged as being in a string
 | 
				
			||||||
 | 
					            return self.text.tag_prevrange("TODO", text_index) or \
 | 
				
			||||||
 | 
					                   "STRING" in self.text.tag_names(text_index)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            # The colorizer is missing: assume the worst
 | 
				
			||||||
 | 
					            return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # If a selection is defined in the text widget, return (start,
 | 
				
			||||||
 | 
					    # end) as Tkinter text indices, otherwise return (None, None)
 | 
				
			||||||
 | 
					    def get_selection_indices(self):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            first = self.text.index("sel.first")
 | 
				
			||||||
 | 
					            last = self.text.index("sel.last")
 | 
				
			||||||
 | 
					            return first, last
 | 
				
			||||||
 | 
					        except TclError:
 | 
				
			||||||
 | 
					            return None, None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Return the text widget's current view of what a tab stop means
 | 
				
			||||||
 | 
					    # (equivalent width in spaces).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_tabwidth(self):
 | 
				
			||||||
 | 
					        current = self.text['tabs'] or TK_TABWIDTH_DEFAULT
 | 
				
			||||||
 | 
					        return int(current)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Set the text widget's current view of what a tab stop means.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_tabwidth(self, newtabwidth):
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        if self.get_tabwidth() != newtabwidth:
 | 
				
			||||||
 | 
					            pixels = text.tk.call("font", "measure", text["font"],
 | 
				
			||||||
 | 
					                                  "-displayof", text.master,
 | 
				
			||||||
 | 
					                                  "n" * newtabwith)
 | 
				
			||||||
 | 
					            text.configure(tabs=pixels)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def prepstr(s):
 | 
				
			||||||
 | 
					    # Helper to extract the underscore from a string, e.g.
 | 
				
			||||||
 | 
					    # prepstr("Co_py") returns (2, "Copy").
 | 
				
			||||||
 | 
					    i = string.find(s, '_')
 | 
				
			||||||
 | 
					    if i >= 0:
 | 
				
			||||||
 | 
					        s = s[:i] + s[i+1:]
 | 
				
			||||||
 | 
					    return i, s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					keynames = {
 | 
				
			||||||
 | 
					 'bracketleft': '[',
 | 
				
			||||||
 | 
					 'bracketright': ']',
 | 
				
			||||||
 | 
					 'slash': '/',
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_accelerator(keydefs, event):
 | 
				
			||||||
 | 
					    keylist = keydefs.get(event)
 | 
				
			||||||
 | 
					    if not keylist:
 | 
				
			||||||
 | 
					        return ""
 | 
				
			||||||
 | 
					    s = keylist[0]
 | 
				
			||||||
 | 
					    s = re.sub(r"-[a-z]\b", lambda m: string.upper(m.group()), s)
 | 
				
			||||||
 | 
					    s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s)
 | 
				
			||||||
 | 
					    s = re.sub("Key-", "", s)
 | 
				
			||||||
 | 
					    s = re.sub("Cancel","Ctrl-Break",s)   # dscherer@cmu.edu
 | 
				
			||||||
 | 
					    s = re.sub("Control-", "Ctrl-", s)
 | 
				
			||||||
 | 
					    s = re.sub("-", "+", s)
 | 
				
			||||||
 | 
					    s = re.sub("><", " ", s)
 | 
				
			||||||
 | 
					    s = re.sub("<", "", s)
 | 
				
			||||||
 | 
					    s = re.sub(">", "", s)
 | 
				
			||||||
 | 
					    return s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def fixwordbreaks(root):
 | 
				
			||||||
 | 
					    # Make sure that Tk's double-click and next/previous word
 | 
				
			||||||
 | 
					    # operations use our definition of a word (i.e. an identifier)
 | 
				
			||||||
 | 
					    tk = root.tk
 | 
				
			||||||
 | 
					    tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded
 | 
				
			||||||
 | 
					    tk.call('set', 'tcl_wordchars', '[a-zA-Z0-9_]')
 | 
				
			||||||
 | 
					    tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_]')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test():
 | 
				
			||||||
 | 
					    root = Tk()
 | 
				
			||||||
 | 
					    fixwordbreaks(root)
 | 
				
			||||||
 | 
					    root.withdraw()
 | 
				
			||||||
 | 
					    if sys.argv[1:]:
 | 
				
			||||||
 | 
					        filename = sys.argv[1]
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        filename = None
 | 
				
			||||||
 | 
					    edit = EditorWindow(root=root, filename=filename)
 | 
				
			||||||
 | 
					    edit.set_close_hook(root.quit)
 | 
				
			||||||
 | 
					    root.mainloop()
 | 
				
			||||||
 | 
					    root.destroy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    test()
 | 
				
			||||||
							
								
								
									
										198
									
								
								Lib/idlelib/ExecBinding.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								Lib/idlelib/ExecBinding.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,198 @@
 | 
				
			||||||
 | 
					"""Extension to execute a script in a separate process
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					David Scherer <dscherer@cmu.edu>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The ExecBinding module, a replacement for ScriptBinding, executes
 | 
				
			||||||
 | 
					  programs in a separate process.  Unlike previous versions, this version
 | 
				
			||||||
 | 
					  communicates with the user process via an RPC protocol (see the 'protocol'
 | 
				
			||||||
 | 
					  module).  The user program is loaded by the 'loader' and 'Remote'
 | 
				
			||||||
 | 
					  modules.  Its standard output and input are directed back to the
 | 
				
			||||||
 | 
					  ExecBinding class through the RPC mechanism and implemented here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  A "stop program" command is provided and bound to control-break.  Closing
 | 
				
			||||||
 | 
					  the output window also stops the running program.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import imp
 | 
				
			||||||
 | 
					import OutputWindow
 | 
				
			||||||
 | 
					import protocol
 | 
				
			||||||
 | 
					import spawn
 | 
				
			||||||
 | 
					import traceback
 | 
				
			||||||
 | 
					import tempfile
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Find Python and the loader.  This should be done as early in execution
 | 
				
			||||||
 | 
					#   as possible, because if the current directory or sys.path is changed
 | 
				
			||||||
 | 
					#   it may no longer be possible to get correct paths for these things.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pyth_exe = spawn.hardpath( sys.executable )
 | 
				
			||||||
 | 
					load_py  = spawn.hardpath( imp.find_module("loader")[1] )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The following mechanism matches loaders up with ExecBindings that are
 | 
				
			||||||
 | 
					#    trying to load something.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					waiting_for_loader = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def loader_connect(client, addr):
 | 
				
			||||||
 | 
					    if waiting_for_loader:
 | 
				
			||||||
 | 
					        a = waiting_for_loader.pop(0)
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            return a.connect(client, addr)
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            return loader_connect(client,addr)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					protocol.publish('ExecBinding', loader_connect)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ExecBinding:
 | 
				
			||||||
 | 
					    keydefs = {
 | 
				
			||||||
 | 
					        '<<run-complete-script>>': ['<F5>'],
 | 
				
			||||||
 | 
					        '<<stop-execution>>': ['<Cancel>'],   #'<Control-c>'
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    menudefs = [
 | 
				
			||||||
 | 
					        ('run', [None,
 | 
				
			||||||
 | 
					                  ('Run program', '<<run-complete-script>>'),
 | 
				
			||||||
 | 
					                  ('Stop program', '<<stop-execution>>'),
 | 
				
			||||||
 | 
					                 ]
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    delegate = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, editwin):
 | 
				
			||||||
 | 
					        self.editwin = editwin
 | 
				
			||||||
 | 
					        self.client = None
 | 
				
			||||||
 | 
					        self.temp = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not hasattr(editwin, 'source_window'):
 | 
				
			||||||
 | 
					            self.delegate = 0
 | 
				
			||||||
 | 
					            self.output = OutputWindow.OnDemandOutputWindow(editwin.flist)
 | 
				
			||||||
 | 
					            self.output.close_hook = self.stopProgram
 | 
				
			||||||
 | 
					            self.output.source_window = editwin
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if (self.editwin.source_window and
 | 
				
			||||||
 | 
					                self.editwin.source_window.extensions.has_key('ExecBinding') and
 | 
				
			||||||
 | 
					                not self.editwin.source_window.extensions['ExecBinding'].delegate):
 | 
				
			||||||
 | 
					                    delegate = self.editwin.source_window.extensions['ExecBinding']
 | 
				
			||||||
 | 
					                    self.run_complete_script_event = delegate.run_complete_script_event
 | 
				
			||||||
 | 
					                    self.stop_execution_event = delegate.stop_execution_event
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __del__(self):
 | 
				
			||||||
 | 
					        self.stopProgram()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def stop_execution_event(self, event):
 | 
				
			||||||
 | 
					        if self.client:
 | 
				
			||||||
 | 
					            self.stopProgram()
 | 
				
			||||||
 | 
					            self.write('\nProgram stopped.\n','stderr')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run_complete_script_event(self, event):
 | 
				
			||||||
 | 
					        filename = self.getfilename()
 | 
				
			||||||
 | 
					        if not filename: return
 | 
				
			||||||
 | 
					        filename = os.path.abspath(filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.stopProgram()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.commands = [ ('run', filename) ]
 | 
				
			||||||
 | 
					        waiting_for_loader.append(self)
 | 
				
			||||||
 | 
					        spawn.spawn( pyth_exe, load_py )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def connect(self, client, addr):
 | 
				
			||||||
 | 
					        # Called by loader_connect() above.  It is remotely possible that
 | 
				
			||||||
 | 
					        #   we get connected to two loaders if the user is running the
 | 
				
			||||||
 | 
					        #   program repeatedly in a short span of time.  In this case, we
 | 
				
			||||||
 | 
					        #   simply return None, refusing to connect and letting the redundant
 | 
				
			||||||
 | 
					        #   loader die.
 | 
				
			||||||
 | 
					        if self.client: return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.client = client
 | 
				
			||||||
 | 
					        client.set_close_hook( self.connect_lost )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        title = self.editwin.short_title()
 | 
				
			||||||
 | 
					        if title:
 | 
				
			||||||
 | 
					            self.output.set_title(title + " Output")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.output.set_title("Output")
 | 
				
			||||||
 | 
					        self.output.write('\n',"stderr")
 | 
				
			||||||
 | 
					        self.output.scroll_clear()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def connect_lost(self):
 | 
				
			||||||
 | 
					        # Called by the client's close hook when the loader closes its
 | 
				
			||||||
 | 
					        #   socket.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # We print a disconnect message only if the output window is already
 | 
				
			||||||
 | 
					        #   open.
 | 
				
			||||||
 | 
					        if self.output.owin and self.output.owin.text:
 | 
				
			||||||
 | 
					            self.output.owin.interrupt()
 | 
				
			||||||
 | 
					            self.output.write("\nProgram disconnected.\n","stderr")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for t in self.temp:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                os.remove(t)
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					        self.temp = []
 | 
				
			||||||
 | 
					        self.client = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_command(self):
 | 
				
			||||||
 | 
					        # Called by Remote to find out what it should be executing.
 | 
				
			||||||
 | 
					        # Later this will be used to implement debugging, interactivity, etc.
 | 
				
			||||||
 | 
					        if self.commands:
 | 
				
			||||||
 | 
					            return self.commands.pop(0)
 | 
				
			||||||
 | 
					        return ('finish',)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def program_exception(self, type, value, tb, first, last):
 | 
				
			||||||
 | 
					        if type == SystemExit: return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for i in range(len(tb)):
 | 
				
			||||||
 | 
					            filename, lineno, name, line = tb[i]
 | 
				
			||||||
 | 
					            if filename in self.temp:
 | 
				
			||||||
 | 
					                filename = 'Untitled'
 | 
				
			||||||
 | 
					            tb[i] = filename, lineno, name, line
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        list = traceback.format_list(tb[first:last])
 | 
				
			||||||
 | 
					        exc = traceback.format_exception_only( type, value )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.write('Traceback (innermost last)\n', 'stderr')
 | 
				
			||||||
 | 
					        for i in (list+exc):
 | 
				
			||||||
 | 
					            self.write(i, 'stderr')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.commands = []
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def write(self, text, tag):
 | 
				
			||||||
 | 
					        self.output.write(text,tag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def readline(self):
 | 
				
			||||||
 | 
					        return self.output.readline()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def stopProgram(self):
 | 
				
			||||||
 | 
					        if self.client:
 | 
				
			||||||
 | 
					          self.client.close()
 | 
				
			||||||
 | 
					          self.client = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getfilename(self):
 | 
				
			||||||
 | 
					        # Save all files which have been named, because they might be modules
 | 
				
			||||||
 | 
					        for edit in self.editwin.flist.inversedict.keys():
 | 
				
			||||||
 | 
					            if edit.io and edit.io.filename and not edit.get_saved():
 | 
				
			||||||
 | 
					                edit.io.save(None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Experimental: execute unnamed buffer
 | 
				
			||||||
 | 
					        if not self.editwin.io.filename:
 | 
				
			||||||
 | 
					            filename = os.path.normcase(os.path.abspath(tempfile.mktemp()))
 | 
				
			||||||
 | 
					            self.temp.append(filename)
 | 
				
			||||||
 | 
					            if self.editwin.io.writefile(filename):
 | 
				
			||||||
 | 
					                return filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # If the file isn't save, we save it.  If it doesn't have a filename,
 | 
				
			||||||
 | 
					        #   the user will be prompted.
 | 
				
			||||||
 | 
					        if self.editwin.io and not self.editwin.get_saved():
 | 
				
			||||||
 | 
					            self.editwin.io.save(None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # If the file *still* isn't saved, we give up.
 | 
				
			||||||
 | 
					        if not self.editwin.get_saved():
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return self.editwin.io.filename
 | 
				
			||||||
							
								
								
									
										150
									
								
								Lib/idlelib/FileList.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								Lib/idlelib/FileList.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,150 @@
 | 
				
			||||||
 | 
					# changes by dscherer@cmu.edu
 | 
				
			||||||
 | 
					#   - FileList.open() takes an optional 3rd parameter action, which is
 | 
				
			||||||
 | 
					#       called instead of creating a new EditorWindow.  This enables
 | 
				
			||||||
 | 
					#       things like 'open in same window'.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					import tkMessageBox
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import WindowList
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<open-new-window>>
 | 
				
			||||||
 | 
					#$ win <Control-n>
 | 
				
			||||||
 | 
					#$ unix <Control-x><Control-n>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# (This is labeled as 'Exit'in the File menu)
 | 
				
			||||||
 | 
					#$ event <<close-all-windows>>
 | 
				
			||||||
 | 
					#$ win <Control-q>
 | 
				
			||||||
 | 
					#$ unix <Control-x><Control-c>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FileList:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    from EditorWindow import EditorWindow
 | 
				
			||||||
 | 
					    EditorWindow.Toplevel = WindowList.ListedToplevel # XXX Patch it!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, root):
 | 
				
			||||||
 | 
					        self.root = root
 | 
				
			||||||
 | 
					        self.dict = {}
 | 
				
			||||||
 | 
					        self.inversedict = {}
 | 
				
			||||||
 | 
					        self.vars = {} # For EditorWindow.getrawvar (shared Tcl variables)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def goodname(self, filename):
 | 
				
			||||||
 | 
					            filename = self.canonize(filename)
 | 
				
			||||||
 | 
					            key = os.path.normcase(filename)
 | 
				
			||||||
 | 
					            if self.dict.has_key(key):
 | 
				
			||||||
 | 
					                edit = self.dict[key]
 | 
				
			||||||
 | 
					                filename = edit.io.filename or filename
 | 
				
			||||||
 | 
					            return filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def open(self, filename, action=None):
 | 
				
			||||||
 | 
					        assert filename
 | 
				
			||||||
 | 
					        filename = self.canonize(filename)
 | 
				
			||||||
 | 
					        if os.path.isdir(filename):
 | 
				
			||||||
 | 
					            tkMessageBox.showerror(
 | 
				
			||||||
 | 
					                "Is A Directory",
 | 
				
			||||||
 | 
					                "The path %s is a directory." % `filename`,
 | 
				
			||||||
 | 
					                master=self.root)
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        key = os.path.normcase(filename)
 | 
				
			||||||
 | 
					        if self.dict.has_key(key):
 | 
				
			||||||
 | 
					            edit = self.dict[key]
 | 
				
			||||||
 | 
					            edit.wakeup()
 | 
				
			||||||
 | 
					            return edit
 | 
				
			||||||
 | 
					        if not os.path.exists(filename):
 | 
				
			||||||
 | 
					            tkMessageBox.showinfo(
 | 
				
			||||||
 | 
					                "New File",
 | 
				
			||||||
 | 
					                "Opening non-existent file %s" % `filename`,
 | 
				
			||||||
 | 
					                master=self.root)
 | 
				
			||||||
 | 
					        if action is None:
 | 
				
			||||||
 | 
					            return self.EditorWindow(self, filename, key)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return action(filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def new(self):
 | 
				
			||||||
 | 
					        return self.EditorWindow(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def new_callback(self, event):
 | 
				
			||||||
 | 
					        self.new()
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close_all_callback(self, event):
 | 
				
			||||||
 | 
					        for edit in self.inversedict.keys():
 | 
				
			||||||
 | 
					            reply = edit.close()
 | 
				
			||||||
 | 
					            if reply == "cancel":
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close_edit(self, edit):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            key = self.inversedict[edit]
 | 
				
			||||||
 | 
					        except KeyError:
 | 
				
			||||||
 | 
					            print "Don't know this EditorWindow object.  (close)"
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if key:
 | 
				
			||||||
 | 
					            del self.dict[key]
 | 
				
			||||||
 | 
					        del self.inversedict[edit]
 | 
				
			||||||
 | 
					        if not self.inversedict:
 | 
				
			||||||
 | 
					            self.root.quit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def filename_changed_edit(self, edit):
 | 
				
			||||||
 | 
					        edit.saved_change_hook()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            key = self.inversedict[edit]
 | 
				
			||||||
 | 
					        except KeyError:
 | 
				
			||||||
 | 
					            print "Don't know this EditorWindow object.  (rename)"
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        filename = edit.io.filename
 | 
				
			||||||
 | 
					        if not filename:
 | 
				
			||||||
 | 
					            if key:
 | 
				
			||||||
 | 
					                del self.dict[key]
 | 
				
			||||||
 | 
					            self.inversedict[edit] = None
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        filename = self.canonize(filename)
 | 
				
			||||||
 | 
					        newkey = os.path.normcase(filename)
 | 
				
			||||||
 | 
					        if newkey == key:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if self.dict.has_key(newkey):
 | 
				
			||||||
 | 
					            conflict = self.dict[newkey]
 | 
				
			||||||
 | 
					            self.inversedict[conflict] = None
 | 
				
			||||||
 | 
					            tkMessageBox.showerror(
 | 
				
			||||||
 | 
					                "Name Conflict",
 | 
				
			||||||
 | 
					                "You now have multiple edit windows open for %s" % `filename`,
 | 
				
			||||||
 | 
					                master=self.root)
 | 
				
			||||||
 | 
					        self.dict[newkey] = edit
 | 
				
			||||||
 | 
					        self.inversedict[edit] = newkey
 | 
				
			||||||
 | 
					        if key:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                del self.dict[key]
 | 
				
			||||||
 | 
					            except KeyError:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def canonize(self, filename):
 | 
				
			||||||
 | 
					        if not os.path.isabs(filename):
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                pwd = os.getcwd()
 | 
				
			||||||
 | 
					            except os.error:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                filename = os.path.join(pwd, filename)
 | 
				
			||||||
 | 
					        return os.path.normpath(filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test():
 | 
				
			||||||
 | 
					    from EditorWindow import fixwordbreaks
 | 
				
			||||||
 | 
					    import sys
 | 
				
			||||||
 | 
					    root = Tk()
 | 
				
			||||||
 | 
					    fixwordbreaks(root)
 | 
				
			||||||
 | 
					    root.withdraw()
 | 
				
			||||||
 | 
					    flist = FileList(root)
 | 
				
			||||||
 | 
					    if sys.argv[1:]:
 | 
				
			||||||
 | 
					        for filename in sys.argv[1:]:
 | 
				
			||||||
 | 
					            flist.open(filename)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        flist.new()
 | 
				
			||||||
 | 
					    if flist.inversedict:
 | 
				
			||||||
 | 
					        root.mainloop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    test()
 | 
				
			||||||
							
								
								
									
										155
									
								
								Lib/idlelib/FormatParagraph.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								Lib/idlelib/FormatParagraph.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,155 @@
 | 
				
			||||||
 | 
					# Extension to format a paragraph
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Does basic, standard text formatting, and also understands Python
 | 
				
			||||||
 | 
					# comment blocks.  Thus, for editing Python source code, this
 | 
				
			||||||
 | 
					# extension is really only suitable for reformatting these comment
 | 
				
			||||||
 | 
					# blocks or triple-quoted strings.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Known problems with comment reformatting:
 | 
				
			||||||
 | 
					# * If there is a selection marked, and the first line of the
 | 
				
			||||||
 | 
					#   selection is not complete, the block will probably not be detected
 | 
				
			||||||
 | 
					#   as comments, and will have the normal "text formatting" rules
 | 
				
			||||||
 | 
					#   applied.
 | 
				
			||||||
 | 
					# * If a comment block has leading whitespace that mixes tabs and
 | 
				
			||||||
 | 
					#   spaces, they will not be considered part of the same block.
 | 
				
			||||||
 | 
					# * Fancy comments, like this bulleted list, arent handled :-)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FormatParagraph:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    menudefs = [
 | 
				
			||||||
 | 
					        ('format', [   # /s/edit/format   dscherer@cmu.edu
 | 
				
			||||||
 | 
					            ('Format Paragraph', '<<format-paragraph>>'),
 | 
				
			||||||
 | 
					         ])
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    keydefs = {
 | 
				
			||||||
 | 
					        '<<format-paragraph>>': ['<Alt-q>'],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    unix_keydefs = {
 | 
				
			||||||
 | 
					        '<<format-paragraph>>': ['<Meta-q>'],
 | 
				
			||||||
 | 
					    } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, editwin):
 | 
				
			||||||
 | 
					        self.editwin = editwin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self):
 | 
				
			||||||
 | 
					        self.editwin = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def format_paragraph_event(self, event):
 | 
				
			||||||
 | 
					        text = self.editwin.text
 | 
				
			||||||
 | 
					        first, last = self.editwin.get_selection_indices()
 | 
				
			||||||
 | 
					        if first and last:
 | 
				
			||||||
 | 
					            data = text.get(first, last)
 | 
				
			||||||
 | 
					            comment_header = ''
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            first, last, comment_header, data = \
 | 
				
			||||||
 | 
					                    find_paragraph(text, text.index("insert"))
 | 
				
			||||||
 | 
					        if comment_header:
 | 
				
			||||||
 | 
					            # Reformat the comment lines - convert to text sans header.
 | 
				
			||||||
 | 
					            lines = string.split(data, "\n")
 | 
				
			||||||
 | 
					            lines = map(lambda st, l=len(comment_header): st[l:], lines)
 | 
				
			||||||
 | 
					            data = string.join(lines, "\n")
 | 
				
			||||||
 | 
					            # Reformat to 70 chars or a 20 char width, whichever is greater.
 | 
				
			||||||
 | 
					            format_width = max(70-len(comment_header), 20)
 | 
				
			||||||
 | 
					            newdata = reformat_paragraph(data, format_width)
 | 
				
			||||||
 | 
					            # re-split and re-insert the comment header.
 | 
				
			||||||
 | 
					            newdata = string.split(newdata, "\n")
 | 
				
			||||||
 | 
					            # If the block ends in a \n, we dont want the comment
 | 
				
			||||||
 | 
					            # prefix inserted after it. (Im not sure it makes sense to
 | 
				
			||||||
 | 
					            # reformat a comment block that isnt made of complete
 | 
				
			||||||
 | 
					            # lines, but whatever!)  Can't think of a clean soltution,
 | 
				
			||||||
 | 
					            # so we hack away
 | 
				
			||||||
 | 
					            block_suffix = ""
 | 
				
			||||||
 | 
					            if not newdata[-1]:
 | 
				
			||||||
 | 
					                block_suffix = "\n"
 | 
				
			||||||
 | 
					                newdata = newdata[:-1]
 | 
				
			||||||
 | 
					            builder = lambda item, prefix=comment_header: prefix+item
 | 
				
			||||||
 | 
					            newdata = string.join(map(builder, newdata), '\n') + block_suffix
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            # Just a normal text format
 | 
				
			||||||
 | 
					            newdata = reformat_paragraph(data)
 | 
				
			||||||
 | 
					        text.tag_remove("sel", "1.0", "end")
 | 
				
			||||||
 | 
					        if newdata != data:
 | 
				
			||||||
 | 
					            text.mark_set("insert", first)
 | 
				
			||||||
 | 
					            text.undo_block_start()
 | 
				
			||||||
 | 
					            text.delete(first, last)
 | 
				
			||||||
 | 
					            text.insert(first, newdata)
 | 
				
			||||||
 | 
					            text.undo_block_stop()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            text.mark_set("insert", last)
 | 
				
			||||||
 | 
					        text.see("insert")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def find_paragraph(text, mark):
 | 
				
			||||||
 | 
					    lineno, col = map(int, string.split(mark, "."))
 | 
				
			||||||
 | 
					    line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
 | 
				
			||||||
 | 
					    while text.compare("%d.0" % lineno, "<", "end") and is_all_white(line):
 | 
				
			||||||
 | 
					        lineno = lineno + 1
 | 
				
			||||||
 | 
					        line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
 | 
				
			||||||
 | 
					    first_lineno = lineno
 | 
				
			||||||
 | 
					    comment_header = get_comment_header(line)
 | 
				
			||||||
 | 
					    comment_header_len = len(comment_header)
 | 
				
			||||||
 | 
					    while get_comment_header(line)==comment_header and \
 | 
				
			||||||
 | 
					              not is_all_white(line[comment_header_len:]):
 | 
				
			||||||
 | 
					        lineno = lineno + 1
 | 
				
			||||||
 | 
					        line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
 | 
				
			||||||
 | 
					    last = "%d.0" % lineno
 | 
				
			||||||
 | 
					    # Search back to beginning of paragraph
 | 
				
			||||||
 | 
					    lineno = first_lineno - 1
 | 
				
			||||||
 | 
					    line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
 | 
				
			||||||
 | 
					    while lineno > 0 and \
 | 
				
			||||||
 | 
					              get_comment_header(line)==comment_header and \
 | 
				
			||||||
 | 
					              not is_all_white(line[comment_header_len:]):
 | 
				
			||||||
 | 
					        lineno = lineno - 1
 | 
				
			||||||
 | 
					        line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
 | 
				
			||||||
 | 
					    first = "%d.0" % (lineno+1)
 | 
				
			||||||
 | 
					    return first, last, comment_header, text.get(first, last)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def reformat_paragraph(data, limit=70):
 | 
				
			||||||
 | 
					    lines = string.split(data, "\n")
 | 
				
			||||||
 | 
					    i = 0
 | 
				
			||||||
 | 
					    n = len(lines)
 | 
				
			||||||
 | 
					    while i < n and is_all_white(lines[i]):
 | 
				
			||||||
 | 
					        i = i+1
 | 
				
			||||||
 | 
					    if i >= n:
 | 
				
			||||||
 | 
					        return data
 | 
				
			||||||
 | 
					    indent1 = get_indent(lines[i])
 | 
				
			||||||
 | 
					    if i+1 < n and not is_all_white(lines[i+1]):
 | 
				
			||||||
 | 
					        indent2 = get_indent(lines[i+1])
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        indent2 = indent1
 | 
				
			||||||
 | 
					    new = lines[:i]
 | 
				
			||||||
 | 
					    partial = indent1
 | 
				
			||||||
 | 
					    while i < n and not is_all_white(lines[i]):
 | 
				
			||||||
 | 
					        # XXX Should take double space after period (etc.) into account
 | 
				
			||||||
 | 
					        words = re.split("(\s+)", lines[i])
 | 
				
			||||||
 | 
					        for j in range(0, len(words), 2):
 | 
				
			||||||
 | 
					            word = words[j]
 | 
				
			||||||
 | 
					            if not word:
 | 
				
			||||||
 | 
					                continue # Can happen when line ends in whitespace
 | 
				
			||||||
 | 
					            if len(string.expandtabs(partial + word)) > limit and \
 | 
				
			||||||
 | 
					               partial != indent1:
 | 
				
			||||||
 | 
					                new.append(string.rstrip(partial))
 | 
				
			||||||
 | 
					                partial = indent2
 | 
				
			||||||
 | 
					            partial = partial + word + " "
 | 
				
			||||||
 | 
					            if j+1 < len(words) and words[j+1] != " ":
 | 
				
			||||||
 | 
					                partial = partial + " "
 | 
				
			||||||
 | 
					        i = i+1
 | 
				
			||||||
 | 
					    new.append(string.rstrip(partial))
 | 
				
			||||||
 | 
					    # XXX Should reformat remaining paragraphs as well
 | 
				
			||||||
 | 
					    new.extend(lines[i:])
 | 
				
			||||||
 | 
					    return string.join(new, "\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def is_all_white(line):
 | 
				
			||||||
 | 
					    return re.match(r"^\s*$", line) is not None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_indent(line):
 | 
				
			||||||
 | 
					    return re.match(r"^(\s*)", line).group()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_comment_header(line):
 | 
				
			||||||
 | 
					    m = re.match(r"^(\s*#*)", line)
 | 
				
			||||||
 | 
					    if m is None: return ""
 | 
				
			||||||
 | 
					    return m.group(1)
 | 
				
			||||||
							
								
								
									
										38
									
								
								Lib/idlelib/FrameViewer.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								Lib/idlelib/FrameViewer.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,38 @@
 | 
				
			||||||
 | 
					from repr import Repr
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FrameViewer:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, root, frame):
 | 
				
			||||||
 | 
					        self.root = root
 | 
				
			||||||
 | 
					        self.frame = frame
 | 
				
			||||||
 | 
					        self.top = Toplevel(self.root)
 | 
				
			||||||
 | 
					        self.repr = Repr()
 | 
				
			||||||
 | 
					        self.repr.maxstring = 60
 | 
				
			||||||
 | 
					        self.load_variables()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def load_variables(self):
 | 
				
			||||||
 | 
					        row = 0
 | 
				
			||||||
 | 
					        if self.frame.f_locals is not self.frame.f_globals:
 | 
				
			||||||
 | 
					            l = Label(self.top, text="Local Variables",
 | 
				
			||||||
 | 
					                      borderwidth=2, relief="raised")
 | 
				
			||||||
 | 
					            l.grid(row=row, column=0, columnspan=2, sticky="ew")
 | 
				
			||||||
 | 
					            row = self.load_names(self.frame.f_locals, row+1)
 | 
				
			||||||
 | 
					        l = Label(self.top, text="Global Variables",
 | 
				
			||||||
 | 
					                  borderwidth=2, relief="raised")
 | 
				
			||||||
 | 
					        l.grid(row=row, column=0, columnspan=2, sticky="ew")
 | 
				
			||||||
 | 
					        row = self.load_names(self.frame.f_globals, row+1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def load_names(self, dict, row):
 | 
				
			||||||
 | 
					        names = dict.keys()
 | 
				
			||||||
 | 
					        names.sort()
 | 
				
			||||||
 | 
					        for name in names:
 | 
				
			||||||
 | 
					            value = dict[name]
 | 
				
			||||||
 | 
					            svalue = self.repr.repr(value)
 | 
				
			||||||
 | 
					            l = Label(self.top, text=name)
 | 
				
			||||||
 | 
					            l.grid(row=row, column=0, sticky="w")
 | 
				
			||||||
 | 
					            l = Entry(self.top, width=60, borderwidth=0)
 | 
				
			||||||
 | 
					            l.insert(0, svalue)
 | 
				
			||||||
 | 
					            l.grid(row=row, column=1, sticky="w")
 | 
				
			||||||
 | 
					            row = row+1
 | 
				
			||||||
 | 
					        return row
 | 
				
			||||||
							
								
								
									
										135
									
								
								Lib/idlelib/GrepDialog.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								Lib/idlelib/GrepDialog.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,135 @@
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import fnmatch
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					import tkMessageBox
 | 
				
			||||||
 | 
					import SearchEngine
 | 
				
			||||||
 | 
					from SearchDialogBase import SearchDialogBase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def grep(text, io=None, flist=None):
 | 
				
			||||||
 | 
					    root = text._root()
 | 
				
			||||||
 | 
					    engine = SearchEngine.get(root)
 | 
				
			||||||
 | 
					    if not hasattr(engine, "_grepdialog"):
 | 
				
			||||||
 | 
					        engine._grepdialog = GrepDialog(root, engine, flist)
 | 
				
			||||||
 | 
					    dialog = engine._grepdialog
 | 
				
			||||||
 | 
					    dialog.open(io)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GrepDialog(SearchDialogBase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    title = "Find in Files Dialog"
 | 
				
			||||||
 | 
					    icon = "Grep"
 | 
				
			||||||
 | 
					    needwrapbutton = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, root, engine, flist):
 | 
				
			||||||
 | 
					        SearchDialogBase.__init__(self, root, engine)
 | 
				
			||||||
 | 
					        self.flist = flist
 | 
				
			||||||
 | 
					        self.globvar = StringVar(root)
 | 
				
			||||||
 | 
					        self.recvar = BooleanVar(root)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def open(self, io=None):
 | 
				
			||||||
 | 
					        SearchDialogBase.open(self, None)
 | 
				
			||||||
 | 
					        if io:
 | 
				
			||||||
 | 
					            path = io.filename or ""
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            path = ""
 | 
				
			||||||
 | 
					        dir, base = os.path.split(path)
 | 
				
			||||||
 | 
					        head, tail = os.path.splitext(base)
 | 
				
			||||||
 | 
					        if not tail:
 | 
				
			||||||
 | 
					            tail = ".py"
 | 
				
			||||||
 | 
					        self.globvar.set(os.path.join(dir, "*" + tail))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_entries(self):
 | 
				
			||||||
 | 
					        SearchDialogBase.create_entries(self)
 | 
				
			||||||
 | 
					        self.globent = self.make_entry("In files:", self.globvar)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_other_buttons(self):
 | 
				
			||||||
 | 
					        f = self.make_frame()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        btn = Checkbutton(f, anchor="w",
 | 
				
			||||||
 | 
					                variable=self.recvar,
 | 
				
			||||||
 | 
					                text="Recurse down subdirectories")
 | 
				
			||||||
 | 
					        btn.pack(side="top", fill="both")
 | 
				
			||||||
 | 
					        btn.select()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_command_buttons(self):
 | 
				
			||||||
 | 
					        SearchDialogBase.create_command_buttons(self)
 | 
				
			||||||
 | 
					        self.make_button("Search Files", self.default_command, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def default_command(self, event=None):
 | 
				
			||||||
 | 
					        prog = self.engine.getprog()
 | 
				
			||||||
 | 
					        if not prog:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        path = self.globvar.get()
 | 
				
			||||||
 | 
					        if not path:
 | 
				
			||||||
 | 
					            self.top.bell()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        from OutputWindow import OutputWindow
 | 
				
			||||||
 | 
					        save = sys.stdout
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            sys.stdout = OutputWindow(self.flist)
 | 
				
			||||||
 | 
					            self.grep_it(prog, path)
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            sys.stdout = save
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def grep_it(self, prog, path):
 | 
				
			||||||
 | 
					        dir, base = os.path.split(path)
 | 
				
			||||||
 | 
					        list = self.findfiles(dir, base, self.recvar.get())
 | 
				
			||||||
 | 
					        list.sort()
 | 
				
			||||||
 | 
					        self.close()
 | 
				
			||||||
 | 
					        pat = self.engine.getpat()
 | 
				
			||||||
 | 
					        print "Searching %s in %s ..." % (`pat`, path)
 | 
				
			||||||
 | 
					        hits = 0
 | 
				
			||||||
 | 
					        for fn in list:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                f = open(fn)
 | 
				
			||||||
 | 
					            except IOError, msg:
 | 
				
			||||||
 | 
					                print msg
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            lineno = 0
 | 
				
			||||||
 | 
					            while 1:
 | 
				
			||||||
 | 
					                block = f.readlines(100000)
 | 
				
			||||||
 | 
					                if not block:
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					                for line in block:
 | 
				
			||||||
 | 
					                    lineno = lineno + 1
 | 
				
			||||||
 | 
					                    if line[-1:] == '\n':
 | 
				
			||||||
 | 
					                        line = line[:-1]
 | 
				
			||||||
 | 
					                    if prog.search(line):
 | 
				
			||||||
 | 
					                        sys.stdout.write("%s: %s: %s\n" % (fn, lineno, line))
 | 
				
			||||||
 | 
					                        hits = hits + 1
 | 
				
			||||||
 | 
					        if hits:
 | 
				
			||||||
 | 
					            if hits == 1:
 | 
				
			||||||
 | 
					                s = ""
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                s = "s"
 | 
				
			||||||
 | 
					            print "Found", hits, "hit%s." % s
 | 
				
			||||||
 | 
					            print "(Hint: right-click to open locations.)"
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            print "No hits."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def findfiles(self, dir, base, rec):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            names = os.listdir(dir or os.curdir)
 | 
				
			||||||
 | 
					        except os.error, msg:
 | 
				
			||||||
 | 
					            print msg
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					        list = []
 | 
				
			||||||
 | 
					        subdirs = []
 | 
				
			||||||
 | 
					        for name in names:
 | 
				
			||||||
 | 
					            fn = os.path.join(dir, name)
 | 
				
			||||||
 | 
					            if os.path.isdir(fn):
 | 
				
			||||||
 | 
					                subdirs.append(fn)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                if fnmatch.fnmatch(name, base):
 | 
				
			||||||
 | 
					                    list.append(fn)
 | 
				
			||||||
 | 
					        if rec:
 | 
				
			||||||
 | 
					            for subdir in subdirs:
 | 
				
			||||||
 | 
					                list.extend(self.findfiles(subdir, base, rec))
 | 
				
			||||||
 | 
					        return list
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self, event=None):
 | 
				
			||||||
 | 
					        if self.top:
 | 
				
			||||||
 | 
					            self.top.grab_release()
 | 
				
			||||||
 | 
					            self.top.withdraw()
 | 
				
			||||||
							
								
								
									
										254
									
								
								Lib/idlelib/IOBinding.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										254
									
								
								Lib/idlelib/IOBinding.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,254 @@
 | 
				
			||||||
 | 
					# changes by dscherer@cmu.edu
 | 
				
			||||||
 | 
					#   - IOBinding.open() replaces the current window with the opened file,
 | 
				
			||||||
 | 
					#     if the current window is both unmodified and unnamed
 | 
				
			||||||
 | 
					#   - IOBinding.loadfile() interprets Windows, UNIX, and Macintosh
 | 
				
			||||||
 | 
					#     end-of-line conventions, instead of relying on the standard library,
 | 
				
			||||||
 | 
					#     which will only understand the local convention.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import tkFileDialog
 | 
				
			||||||
 | 
					import tkMessageBox
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<open-window-from-file>>
 | 
				
			||||||
 | 
					#$ win <Control-o>
 | 
				
			||||||
 | 
					#$ unix <Control-x><Control-f>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<save-window>>
 | 
				
			||||||
 | 
					#$ win <Control-s>
 | 
				
			||||||
 | 
					#$ unix <Control-x><Control-s>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<save-window-as-file>>
 | 
				
			||||||
 | 
					#$ win <Alt-s>
 | 
				
			||||||
 | 
					#$ unix <Control-x><Control-w>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<save-copy-of-window-as-file>>
 | 
				
			||||||
 | 
					#$ win <Alt-Shift-s>
 | 
				
			||||||
 | 
					#$ unix <Control-x><w>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IOBinding:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, editwin):
 | 
				
			||||||
 | 
					        self.editwin = editwin
 | 
				
			||||||
 | 
					        self.text = editwin.text
 | 
				
			||||||
 | 
					        self.__id_open = self.text.bind("<<open-window-from-file>>", self.open)
 | 
				
			||||||
 | 
					        self.__id_save = self.text.bind("<<save-window>>", self.save)
 | 
				
			||||||
 | 
					        self.__id_saveas = self.text.bind("<<save-window-as-file>>",
 | 
				
			||||||
 | 
					                                          self.save_as)
 | 
				
			||||||
 | 
					        self.__id_savecopy = self.text.bind("<<save-copy-of-window-as-file>>",
 | 
				
			||||||
 | 
					                                            self.save_a_copy)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self):
 | 
				
			||||||
 | 
					        # Undo command bindings
 | 
				
			||||||
 | 
					        self.text.unbind("<<open-window-from-file>>", self.__id_open)
 | 
				
			||||||
 | 
					        self.text.unbind("<<save-window>>", self.__id_save)
 | 
				
			||||||
 | 
					        self.text.unbind("<<save-window-as-file>>",self.__id_saveas)
 | 
				
			||||||
 | 
					        self.text.unbind("<<save-copy-of-window-as-file>>", self.__id_savecopy)
 | 
				
			||||||
 | 
					        # Break cycles
 | 
				
			||||||
 | 
					        self.editwin = None
 | 
				
			||||||
 | 
					        self.text = None
 | 
				
			||||||
 | 
					        self.filename_change_hook = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_saved(self):
 | 
				
			||||||
 | 
					        return self.editwin.get_saved()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_saved(self, flag):
 | 
				
			||||||
 | 
					        self.editwin.set_saved(flag)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def reset_undo(self):
 | 
				
			||||||
 | 
					        self.editwin.reset_undo()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    filename_change_hook = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_filename_change_hook(self, hook):
 | 
				
			||||||
 | 
					        self.filename_change_hook = hook
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    filename = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_filename(self, filename):
 | 
				
			||||||
 | 
					        self.filename = filename
 | 
				
			||||||
 | 
					        self.set_saved(1)
 | 
				
			||||||
 | 
					        if self.filename_change_hook:
 | 
				
			||||||
 | 
					            self.filename_change_hook()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def open(self, event):
 | 
				
			||||||
 | 
					        if self.editwin.flist:
 | 
				
			||||||
 | 
					            filename = self.askopenfile()
 | 
				
			||||||
 | 
					            if filename:
 | 
				
			||||||
 | 
					                # if the current window has no filename and hasn't been
 | 
				
			||||||
 | 
					                #   modified, we replace it's contents (no loss).  Otherwise
 | 
				
			||||||
 | 
					                #   we open a new window.
 | 
				
			||||||
 | 
					                if not self.filename and self.get_saved():
 | 
				
			||||||
 | 
					                    self.editwin.flist.open(filename, self.loadfile)
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    self.editwin.flist.open(filename)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                self.text.focus_set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					        # Code for use outside IDLE:
 | 
				
			||||||
 | 
					        if self.get_saved():
 | 
				
			||||||
 | 
					            reply = self.maybesave()
 | 
				
			||||||
 | 
					            if reply == "cancel":
 | 
				
			||||||
 | 
					                self.text.focus_set()
 | 
				
			||||||
 | 
					                return "break"
 | 
				
			||||||
 | 
					        filename = self.askopenfile()
 | 
				
			||||||
 | 
					        if filename:
 | 
				
			||||||
 | 
					            self.loadfile(filename)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.text.focus_set()
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def loadfile(self, filename):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            # open the file in binary mode so that we can handle
 | 
				
			||||||
 | 
					            #   end-of-line convention ourselves.
 | 
				
			||||||
 | 
					            f = open(filename,'rb')
 | 
				
			||||||
 | 
					            chars = f.read()
 | 
				
			||||||
 | 
					            f.close()
 | 
				
			||||||
 | 
					        except IOError, msg:
 | 
				
			||||||
 | 
					            tkMessageBox.showerror("I/O Error", str(msg), master=self.text)
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # We now convert all end-of-lines to '\n's
 | 
				
			||||||
 | 
					        eol = r"(\r\n)|\n|\r"  # \r\n (Windows), \n (UNIX), or \r (Mac)
 | 
				
			||||||
 | 
					        chars = re.compile( eol ).sub( r"\n", chars )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.text.delete("1.0", "end")
 | 
				
			||||||
 | 
					        self.set_filename(None)
 | 
				
			||||||
 | 
					        self.text.insert("1.0", chars)
 | 
				
			||||||
 | 
					        self.reset_undo()
 | 
				
			||||||
 | 
					        self.set_filename(filename)
 | 
				
			||||||
 | 
					        self.text.mark_set("insert", "1.0")
 | 
				
			||||||
 | 
					        self.text.see("insert")
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def maybesave(self):
 | 
				
			||||||
 | 
					        if self.get_saved():
 | 
				
			||||||
 | 
					            return "yes"
 | 
				
			||||||
 | 
					        message = "Do you want to save %s before closing?" % (
 | 
				
			||||||
 | 
					            self.filename or "this untitled document")
 | 
				
			||||||
 | 
					        m = tkMessageBox.Message(
 | 
				
			||||||
 | 
					            title="Save On Close",
 | 
				
			||||||
 | 
					            message=message,
 | 
				
			||||||
 | 
					            icon=tkMessageBox.QUESTION,
 | 
				
			||||||
 | 
					            type=tkMessageBox.YESNOCANCEL,
 | 
				
			||||||
 | 
					            master=self.text)
 | 
				
			||||||
 | 
					        reply = m.show()
 | 
				
			||||||
 | 
					        if reply == "yes":
 | 
				
			||||||
 | 
					            self.save(None)
 | 
				
			||||||
 | 
					            if not self.get_saved():
 | 
				
			||||||
 | 
					                reply = "cancel"
 | 
				
			||||||
 | 
					        self.text.focus_set()
 | 
				
			||||||
 | 
					        return reply
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save(self, event):
 | 
				
			||||||
 | 
					        if not self.filename:
 | 
				
			||||||
 | 
					            self.save_as(event)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if self.writefile(self.filename):
 | 
				
			||||||
 | 
					                self.set_saved(1)
 | 
				
			||||||
 | 
					        self.text.focus_set()
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save_as(self, event):
 | 
				
			||||||
 | 
					        filename = self.asksavefile()
 | 
				
			||||||
 | 
					        if filename:
 | 
				
			||||||
 | 
					            if self.writefile(filename):
 | 
				
			||||||
 | 
					                self.set_filename(filename)
 | 
				
			||||||
 | 
					                self.set_saved(1)
 | 
				
			||||||
 | 
					        self.text.focus_set()
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save_a_copy(self, event):
 | 
				
			||||||
 | 
					        filename = self.asksavefile()
 | 
				
			||||||
 | 
					        if filename:
 | 
				
			||||||
 | 
					            self.writefile(filename)
 | 
				
			||||||
 | 
					        self.text.focus_set()
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def writefile(self, filename):
 | 
				
			||||||
 | 
					        self.fixlastline()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            f = open(filename, "w")
 | 
				
			||||||
 | 
					            chars = self.text.get("1.0", "end-1c")
 | 
				
			||||||
 | 
					            f.write(chars)
 | 
				
			||||||
 | 
					            f.close()
 | 
				
			||||||
 | 
					            ## print "saved to", `filename`
 | 
				
			||||||
 | 
					            return 1
 | 
				
			||||||
 | 
					        except IOError, msg:
 | 
				
			||||||
 | 
					            tkMessageBox.showerror("I/O Error", str(msg),
 | 
				
			||||||
 | 
					                                   master=self.text)
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def fixlastline(self):
 | 
				
			||||||
 | 
					        c = self.text.get("end-2c")
 | 
				
			||||||
 | 
					        if c != '\n':
 | 
				
			||||||
 | 
					            self.text.insert("end-1c", "\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    opendialog = None
 | 
				
			||||||
 | 
					    savedialog = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    filetypes = [
 | 
				
			||||||
 | 
					        ("Python and text files", "*.py *.pyw *.txt", "TEXT"),
 | 
				
			||||||
 | 
					        ("All text files", "*", "TEXT"),
 | 
				
			||||||
 | 
					        ("All files", "*"),
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def askopenfile(self):
 | 
				
			||||||
 | 
					        dir, base = self.defaultfilename("open")
 | 
				
			||||||
 | 
					        if not self.opendialog:
 | 
				
			||||||
 | 
					            self.opendialog = tkFileDialog.Open(master=self.text,
 | 
				
			||||||
 | 
					                                                filetypes=self.filetypes)
 | 
				
			||||||
 | 
					        return self.opendialog.show(initialdir=dir, initialfile=base)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def defaultfilename(self, mode="open"):
 | 
				
			||||||
 | 
					        if self.filename:
 | 
				
			||||||
 | 
					            return os.path.split(self.filename)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                pwd = os.getcwd()
 | 
				
			||||||
 | 
					            except os.error:
 | 
				
			||||||
 | 
					                pwd = ""
 | 
				
			||||||
 | 
					            return pwd, ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def asksavefile(self):
 | 
				
			||||||
 | 
					        dir, base = self.defaultfilename("save")
 | 
				
			||||||
 | 
					        if not self.savedialog:
 | 
				
			||||||
 | 
					            self.savedialog = tkFileDialog.SaveAs(master=self.text,
 | 
				
			||||||
 | 
					                                                  filetypes=self.filetypes)
 | 
				
			||||||
 | 
					        return self.savedialog.show(initialdir=dir, initialfile=base)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test():
 | 
				
			||||||
 | 
					    from Tkinter import *
 | 
				
			||||||
 | 
					    root = Tk()
 | 
				
			||||||
 | 
					    class MyEditWin:
 | 
				
			||||||
 | 
					        def __init__(self, text):
 | 
				
			||||||
 | 
					            self.text = text
 | 
				
			||||||
 | 
					            self.flist = None
 | 
				
			||||||
 | 
					            self.text.bind("<Control-o>", self.open)
 | 
				
			||||||
 | 
					            self.text.bind("<Control-s>", self.save)
 | 
				
			||||||
 | 
					            self.text.bind("<Alt-s>", self.save_as)
 | 
				
			||||||
 | 
					            self.text.bind("<Alt-z>", self.save_a_copy)
 | 
				
			||||||
 | 
					        def get_saved(self): return 0
 | 
				
			||||||
 | 
					        def set_saved(self, flag): pass
 | 
				
			||||||
 | 
					        def reset_undo(self): pass
 | 
				
			||||||
 | 
					        def open(self, event):
 | 
				
			||||||
 | 
					            self.text.event_generate("<<open-window-from-file>>")
 | 
				
			||||||
 | 
					        def save(self, event):
 | 
				
			||||||
 | 
					            self.text.event_generate("<<save-window>>")
 | 
				
			||||||
 | 
					        def save_as(self, event):
 | 
				
			||||||
 | 
					            self.text.event_generate("<<save-window-as-file>>")
 | 
				
			||||||
 | 
					        def save_a_copy(self, event):
 | 
				
			||||||
 | 
					            self.text.event_generate("<<save-copy-of-window-as-file>>")
 | 
				
			||||||
 | 
					    text = Text(root)
 | 
				
			||||||
 | 
					    text.pack()
 | 
				
			||||||
 | 
					    text.focus_set()
 | 
				
			||||||
 | 
					    editwin = MyEditWin(text)
 | 
				
			||||||
 | 
					    io = IOBinding(editwin)
 | 
				
			||||||
 | 
					    root.mainloop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    test()
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								Lib/idlelib/Icons/folder.gif
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Lib/idlelib/Icons/folder.gif
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 120 B  | 
							
								
								
									
										
											BIN
										
									
								
								Lib/idlelib/Icons/minusnode.gif
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Lib/idlelib/Icons/minusnode.gif
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 75 B  | 
							
								
								
									
										
											BIN
										
									
								
								Lib/idlelib/Icons/openfolder.gif
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Lib/idlelib/Icons/openfolder.gif
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 125 B  | 
							
								
								
									
										
											BIN
										
									
								
								Lib/idlelib/Icons/plusnode.gif
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Lib/idlelib/Icons/plusnode.gif
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 79 B  | 
							
								
								
									
										
											BIN
										
									
								
								Lib/idlelib/Icons/python.gif
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Lib/idlelib/Icons/python.gif
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 895 B  | 
							
								
								
									
										
											BIN
										
									
								
								Lib/idlelib/Icons/tk.gif
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								Lib/idlelib/Icons/tk.gif
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 85 B  | 
							
								
								
									
										113
									
								
								Lib/idlelib/IdleConf.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								Lib/idlelib/IdleConf.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,113 @@
 | 
				
			||||||
 | 
					"""Provides access to configuration information"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					from ConfigParser import ConfigParser, NoOptionError, NoSectionError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class IdleConfParser(ConfigParser):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # these conf sections do not define extensions!
 | 
				
			||||||
 | 
					    builtin_sections = {}
 | 
				
			||||||
 | 
					    for section in ('EditorWindow', 'Colors'):
 | 
				
			||||||
 | 
					        builtin_sections[section] = section
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def getcolor(self, sec, name):
 | 
				
			||||||
 | 
					        """Return a dictionary with foreground and background colors
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The return value is appropriate for passing to Tkinter in, e.g.,
 | 
				
			||||||
 | 
					        a tag_config call.
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
						fore = self.getdef(sec, name + "-foreground")
 | 
				
			||||||
 | 
						back = self.getdef(sec, name + "-background")
 | 
				
			||||||
 | 
					        return {"foreground": fore,
 | 
				
			||||||
 | 
					                "background": back}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getdef(self, sec, options, raw=0, vars=None, default=None):
 | 
				
			||||||
 | 
					        """Get an option value for given section or return default"""
 | 
				
			||||||
 | 
						try:
 | 
				
			||||||
 | 
					            return self.get(sec, options, raw, vars)
 | 
				
			||||||
 | 
						except (NoSectionError, NoOptionError):
 | 
				
			||||||
 | 
						    return default
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getsection(self, section):
 | 
				
			||||||
 | 
					        """Return a SectionConfigParser object"""
 | 
				
			||||||
 | 
					        return SectionConfigParser(section, self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getextensions(self):
 | 
				
			||||||
 | 
					        exts = []
 | 
				
			||||||
 | 
					        for sec in self.sections():
 | 
				
			||||||
 | 
					            if self.builtin_sections.has_key(sec):
 | 
				
			||||||
 | 
							continue
 | 
				
			||||||
 | 
						    # enable is a bool, but it may not be defined
 | 
				
			||||||
 | 
						    if self.getdef(sec, 'enable') != '0':
 | 
				
			||||||
 | 
							exts.append(sec)
 | 
				
			||||||
 | 
					        return exts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def reload(self):
 | 
				
			||||||
 | 
					        global idleconf
 | 
				
			||||||
 | 
					        idleconf = IdleConfParser()
 | 
				
			||||||
 | 
					        load(_dir) # _dir is a global holding the last directory loaded
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SectionConfigParser:
 | 
				
			||||||
 | 
					    """A ConfigParser object specialized for one section
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    This class has all the get methods that a regular ConfigParser does,
 | 
				
			||||||
 | 
					    but without requiring a section argument.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    def __init__(self, section, config):
 | 
				
			||||||
 | 
					        self.section = section
 | 
				
			||||||
 | 
					        self.config = config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def options(self):
 | 
				
			||||||
 | 
					        return self.config.options(self.section)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get(self, options, raw=0, vars=None):
 | 
				
			||||||
 | 
					        return self.config.get(self.section, options, raw, vars)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getdef(self, options, raw=0, vars=None, default=None):
 | 
				
			||||||
 | 
					        return self.config.getdef(self.section, options, raw, vars, default)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getint(self, option):
 | 
				
			||||||
 | 
					        return self.config.getint(self.section, option)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def getfloat(self, option):
 | 
				
			||||||
 | 
					        return self.config.getint(self.section, option)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def getboolean(self, option):
 | 
				
			||||||
 | 
					        return self.config.getint(self.section, option)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getcolor(self, option):
 | 
				
			||||||
 | 
					        return self.config.getcolor(self.section, option)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def load(dir):
 | 
				
			||||||
 | 
					    """Load IDLE configuration files based on IDLE install in dir
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Attempts to load two config files:
 | 
				
			||||||
 | 
					    dir/config.txt
 | 
				
			||||||
 | 
					    dir/config-[win/mac/unix].txt
 | 
				
			||||||
 | 
					    dir/config-%(sys.platform)s.txt
 | 
				
			||||||
 | 
					    ~/.idle
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					    global _dir
 | 
				
			||||||
 | 
					    _dir = dir
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if sys.platform[:3] == 'win':
 | 
				
			||||||
 | 
					        genplatfile = os.path.join(dir, "config-win.txt")
 | 
				
			||||||
 | 
					    # XXX don't know what the platform string is on a Mac
 | 
				
			||||||
 | 
					    elif sys.platform[:3] == 'mac':
 | 
				
			||||||
 | 
					        genplatfile = os.path.join(dir, "config-mac.txt")
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        genplatfile = os.path.join(dir, "config-unix.txt")
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    platfile = os.path.join(dir, "config-%s.txt" % sys.platform)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        homedir = os.environ['HOME']
 | 
				
			||||||
 | 
					    except KeyError:
 | 
				
			||||||
 | 
					        homedir = os.getcwd()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    idleconf.read((os.path.join(dir, "config.txt"), genplatfile, platfile,
 | 
				
			||||||
 | 
					                   os.path.join(homedir, ".idle")))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					idleconf = IdleConfParser()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										89
									
								
								Lib/idlelib/IdleHistory.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								Lib/idlelib/IdleHistory.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,89 @@
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class History:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, text, output_sep = "\n"):
 | 
				
			||||||
 | 
					        self.text = text
 | 
				
			||||||
 | 
					        self.history = []
 | 
				
			||||||
 | 
					        self.history_prefix = None
 | 
				
			||||||
 | 
					        self.history_pointer = None
 | 
				
			||||||
 | 
					        self.output_sep = output_sep
 | 
				
			||||||
 | 
					        text.bind("<<history-previous>>", self.history_prev)
 | 
				
			||||||
 | 
					        text.bind("<<history-next>>", self.history_next)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def history_next(self, event):
 | 
				
			||||||
 | 
					        self.history_do(0)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def history_prev(self, event):
 | 
				
			||||||
 | 
					        self.history_do(1)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _get_source(self, start, end):
 | 
				
			||||||
 | 
					        # Get source code from start index to end index.  Lines in the
 | 
				
			||||||
 | 
					        # text control may be separated by sys.ps2 .
 | 
				
			||||||
 | 
					        lines = string.split(self.text.get(start, end), self.output_sep)
 | 
				
			||||||
 | 
					        return string.join(lines, "\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _put_source(self, where, source):
 | 
				
			||||||
 | 
					        output = string.join(string.split(source, "\n"), self.output_sep)
 | 
				
			||||||
 | 
					        self.text.insert(where, output)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def history_do(self, reverse):
 | 
				
			||||||
 | 
					        nhist = len(self.history)
 | 
				
			||||||
 | 
					        pointer = self.history_pointer
 | 
				
			||||||
 | 
					        prefix = self.history_prefix
 | 
				
			||||||
 | 
					        if pointer is not None and prefix is not None:
 | 
				
			||||||
 | 
					            if self.text.compare("insert", "!=", "end-1c") or \
 | 
				
			||||||
 | 
					               self._get_source("iomark", "end-1c") != self.history[pointer]:
 | 
				
			||||||
 | 
					                pointer = prefix = None
 | 
				
			||||||
 | 
					        if pointer is None or prefix is None:
 | 
				
			||||||
 | 
					            prefix = self._get_source("iomark", "end-1c")
 | 
				
			||||||
 | 
					            if reverse:
 | 
				
			||||||
 | 
					                pointer = nhist
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                pointer = -1
 | 
				
			||||||
 | 
					        nprefix = len(prefix)
 | 
				
			||||||
 | 
					        while 1:
 | 
				
			||||||
 | 
					            if reverse:
 | 
				
			||||||
 | 
					                pointer = pointer - 1
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                pointer = pointer + 1
 | 
				
			||||||
 | 
					            if pointer < 0 or pointer >= nhist:
 | 
				
			||||||
 | 
					                self.text.bell()
 | 
				
			||||||
 | 
					                if self._get_source("iomark", "end-1c") != prefix:
 | 
				
			||||||
 | 
					                    self.text.delete("iomark", "end-1c")
 | 
				
			||||||
 | 
					                    self._put_source("iomark", prefix)
 | 
				
			||||||
 | 
					                pointer = prefix = None
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            item = self.history[pointer]
 | 
				
			||||||
 | 
					            if item[:nprefix] == prefix and len(item) > nprefix:
 | 
				
			||||||
 | 
					                self.text.delete("iomark", "end-1c")
 | 
				
			||||||
 | 
					                self._put_source("iomark", item)
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					        self.text.mark_set("insert", "end-1c")
 | 
				
			||||||
 | 
					        self.text.see("insert")
 | 
				
			||||||
 | 
					        self.text.tag_remove("sel", "1.0", "end")
 | 
				
			||||||
 | 
					        self.history_pointer = pointer
 | 
				
			||||||
 | 
					        self.history_prefix = prefix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def history_store(self, source):
 | 
				
			||||||
 | 
					        source = string.strip(source)
 | 
				
			||||||
 | 
					        if len(source) > 2:
 | 
				
			||||||
 | 
					            # avoid duplicates
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                self.history.remove(source)
 | 
				
			||||||
 | 
					            except ValueError:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					            self.history.append(source)
 | 
				
			||||||
 | 
					        self.history_pointer = None
 | 
				
			||||||
 | 
					        self.history_prefix = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def recall(self, s):
 | 
				
			||||||
 | 
					        s = string.strip(s)
 | 
				
			||||||
 | 
					        self.text.tag_remove("sel", "1.0", "end")
 | 
				
			||||||
 | 
					        self.text.delete("iomark", "end-1c")
 | 
				
			||||||
 | 
					        self.text.mark_set("insert", "end-1c")
 | 
				
			||||||
 | 
					        self.text.insert("insert", s)
 | 
				
			||||||
 | 
					        self.text.see("insert")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										138
									
								
								Lib/idlelib/MultiScrolledLists.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								Lib/idlelib/MultiScrolledLists.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,138 @@
 | 
				
			||||||
 | 
					# One or more ScrolledLists with HSeparators between them.
 | 
				
			||||||
 | 
					# There is a hierarchical relationship between them:
 | 
				
			||||||
 | 
					# the right list displays the substructure of the selected item
 | 
				
			||||||
 | 
					# in the left list.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					from WindowList import ListedToplevel
 | 
				
			||||||
 | 
					from Separator import HSeparator
 | 
				
			||||||
 | 
					from ScrolledList import ScrolledList
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MultiScrolledLists:
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def __init__(self, root, nlists=2):
 | 
				
			||||||
 | 
					        assert nlists >= 1
 | 
				
			||||||
 | 
					        self.root = root
 | 
				
			||||||
 | 
					        self.nlists = nlists
 | 
				
			||||||
 | 
					        self.path = []
 | 
				
			||||||
 | 
					        # create top
 | 
				
			||||||
 | 
					        self.top = top = ListedToplevel(root)
 | 
				
			||||||
 | 
					        top.protocol("WM_DELETE_WINDOW", self.close)
 | 
				
			||||||
 | 
					        top.bind("<Escape>", self.close)
 | 
				
			||||||
 | 
					        self.settitle()
 | 
				
			||||||
 | 
					        # create frames and separators in between
 | 
				
			||||||
 | 
					        self.frames = []
 | 
				
			||||||
 | 
					        self.separators = []
 | 
				
			||||||
 | 
					        last = top
 | 
				
			||||||
 | 
					        for i in range(nlists-1):
 | 
				
			||||||
 | 
					            sepa = HSeparator(last)
 | 
				
			||||||
 | 
					            self.separators.append(sepa)
 | 
				
			||||||
 | 
					            frame, last = sepa.parts()
 | 
				
			||||||
 | 
					            self.frames.append(frame)
 | 
				
			||||||
 | 
					        self.frames.append(last)
 | 
				
			||||||
 | 
					        # create labels and lists
 | 
				
			||||||
 | 
					        self.labels = []
 | 
				
			||||||
 | 
					        self.lists = []
 | 
				
			||||||
 | 
					        for i in range(nlists):
 | 
				
			||||||
 | 
					            frame = self.frames[i]
 | 
				
			||||||
 | 
					            label = Label(frame, text=self.subtitle(i),
 | 
				
			||||||
 | 
					                relief="groove", borderwidth=2)
 | 
				
			||||||
 | 
					            label.pack(fill="x")
 | 
				
			||||||
 | 
					            self.labels.append(label)
 | 
				
			||||||
 | 
					            list = ScrolledList(frame, width=self.width(i),
 | 
				
			||||||
 | 
					                height=self.height(i))
 | 
				
			||||||
 | 
					            self.lists.append(list)
 | 
				
			||||||
 | 
					            list.on_select = \
 | 
				
			||||||
 | 
					                lambda index, i=i, self=self: self.on_select(index, i)
 | 
				
			||||||
 | 
					            list.on_double = \
 | 
				
			||||||
 | 
					                lambda index, i=i, self=self: self.on_double(index, i)
 | 
				
			||||||
 | 
					        # fill leftmost list (rest get filled on demand)
 | 
				
			||||||
 | 
					        self.fill(0)
 | 
				
			||||||
 | 
					        # XXX one after_idle isn't enough; two are...
 | 
				
			||||||
 | 
					        top.after_idle(self.call_pack_propagate_1)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def call_pack_propagate_1(self):
 | 
				
			||||||
 | 
					        self.top.after_idle(self.call_pack_propagate)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def call_pack_propagate(self):
 | 
				
			||||||
 | 
					        for frame in self.frames:
 | 
				
			||||||
 | 
					            frame.pack_propagate(0)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def close(self, event=None):
 | 
				
			||||||
 | 
					        self.top.destroy()
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def settitle(self):
 | 
				
			||||||
 | 
					        short = self.shorttitle()
 | 
				
			||||||
 | 
					        long = self.longtitle()
 | 
				
			||||||
 | 
					        if short and long:
 | 
				
			||||||
 | 
					            title = short + " - " + long
 | 
				
			||||||
 | 
					        elif short:
 | 
				
			||||||
 | 
					            title = short
 | 
				
			||||||
 | 
					        elif long:
 | 
				
			||||||
 | 
					            title = long
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            title = "Untitled"
 | 
				
			||||||
 | 
					        icon = short or long or title
 | 
				
			||||||
 | 
					        self.top.wm_title(title)
 | 
				
			||||||
 | 
					        self.top.wm_iconname(icon)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def longtitle(self):
 | 
				
			||||||
 | 
					        # override this
 | 
				
			||||||
 | 
					        return "Multi Scrolled Lists"
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def shorttitle(self):
 | 
				
			||||||
 | 
					        # override this
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def width(self, i):
 | 
				
			||||||
 | 
					        # override this
 | 
				
			||||||
 | 
					        return 20
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def height(self, i):
 | 
				
			||||||
 | 
					        # override this
 | 
				
			||||||
 | 
					        return 10
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def subtitle(self, i):
 | 
				
			||||||
 | 
					        # override this
 | 
				
			||||||
 | 
					        return "Column %d" % i
 | 
				
			||||||
 | 
					     
 | 
				
			||||||
 | 
					    def fill(self, i):
 | 
				
			||||||
 | 
					        for k in range(i, self.nlists):
 | 
				
			||||||
 | 
					            self.lists[k].clear()
 | 
				
			||||||
 | 
					            self.labels[k].configure(text=self.subtitle(k))
 | 
				
			||||||
 | 
					        list = self.lists[i]
 | 
				
			||||||
 | 
					        l = self.items(i)
 | 
				
			||||||
 | 
					        for s in l:
 | 
				
			||||||
 | 
					            list.append(s)
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					    def on_select(self, index, i):
 | 
				
			||||||
 | 
					        item = self.lists[i].get(index)
 | 
				
			||||||
 | 
					        del self.path[i:]
 | 
				
			||||||
 | 
					        self.path.append(item)
 | 
				
			||||||
 | 
					        if i+1 < self.nlists:
 | 
				
			||||||
 | 
					            self.fill(i+1)
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					    def items(self, i):
 | 
				
			||||||
 | 
					        # override this
 | 
				
			||||||
 | 
					        l = []
 | 
				
			||||||
 | 
					        for k in range(10):
 | 
				
			||||||
 | 
					            s = str(k)
 | 
				
			||||||
 | 
					            if i > 0:
 | 
				
			||||||
 | 
					                s = self.path[i-1] + "." + s
 | 
				
			||||||
 | 
					            l.append(s)
 | 
				
			||||||
 | 
					        return l
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def on_double(self, index, i):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    root = Tk()
 | 
				
			||||||
 | 
					    quit = Button(root, text="Exit", command=root.destroy)
 | 
				
			||||||
 | 
					    quit.pack()
 | 
				
			||||||
 | 
					    MultiScrolledLists(root, 4)
 | 
				
			||||||
 | 
					    root.mainloop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										32
									
								
								Lib/idlelib/MultiStatusBar.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								Lib/idlelib/MultiStatusBar.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,32 @@
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class MultiStatusBar(Frame):
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						def __init__(self, master=None, **kw):
 | 
				
			||||||
 | 
							if master is None:
 | 
				
			||||||
 | 
								master = Tk()
 | 
				
			||||||
 | 
							apply(Frame.__init__, (self, master), kw)
 | 
				
			||||||
 | 
							self.labels = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						def set_label(self, name, text='', side=LEFT):
 | 
				
			||||||
 | 
							if not self.labels.has_key(name):
 | 
				
			||||||
 | 
								label = Label(self, bd=1, relief=SUNKEN, anchor=W)
 | 
				
			||||||
 | 
								label.pack(side=side)
 | 
				
			||||||
 | 
								self.labels[name] = label
 | 
				
			||||||
 | 
							else:
 | 
				
			||||||
 | 
								label = self.labels[name]
 | 
				
			||||||
 | 
							label.config(text=text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _test():
 | 
				
			||||||
 | 
						b = Frame()
 | 
				
			||||||
 | 
						c = Text(b)
 | 
				
			||||||
 | 
						c.pack(side=TOP)
 | 
				
			||||||
 | 
						a = MultiStatusBar(b)
 | 
				
			||||||
 | 
						a.set_label("one", "hello")
 | 
				
			||||||
 | 
						a.set_label("two", "world")
 | 
				
			||||||
 | 
						a.pack(side=BOTTOM, fill=X)
 | 
				
			||||||
 | 
						b.pack()
 | 
				
			||||||
 | 
						b.mainloop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
						_test()
 | 
				
			||||||
							
								
								
									
										130
									
								
								Lib/idlelib/NEWS.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								Lib/idlelib/NEWS.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,130 @@
 | 
				
			||||||
 | 
					(For a more detailed change log, see the file ChangeLog.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					----------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					New in IDLE 0.5 (2/15/2000)
 | 
				
			||||||
 | 
					-------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tons of stuff, much of it contributed by Tim Peters and Mark Hammond:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Status bar, displaying current line/column (Moshe Zadka).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Better stack viewer, using tree widget.  (XXX Only used by Stack
 | 
				
			||||||
 | 
					Viewer menu, not by the debugger.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Format paragraph now recognizes Python block comments and reformats
 | 
				
			||||||
 | 
					them correctly (MH)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- New version of pyclbr.py parses top-level functions and understands
 | 
				
			||||||
 | 
					much more of Python's syntax; this is reflected in the class and path
 | 
				
			||||||
 | 
					browsers (TP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Much better auto-indent; knows how to indent the insides of
 | 
				
			||||||
 | 
					multi-line statements (TP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Call tip window pops up when you type the name of a known function
 | 
				
			||||||
 | 
					followed by an open parenthesis.  Hit ESC or click elsewhere in the
 | 
				
			||||||
 | 
					window to close the tip window (MH)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Comment out region now inserts ## to make it stand out more (TP)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- New path and class browsers based on a tree widget that looks
 | 
				
			||||||
 | 
					familiar to Windows users
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Reworked script running commands to be more intuitive: I/O now
 | 
				
			||||||
 | 
					always goes to the *Python Shell* window, and raw_input() works
 | 
				
			||||||
 | 
					correctly.  You use F5 to import/reload a module: this adds the module
 | 
				
			||||||
 | 
					name to the __main__ namespace.  You use Control-F5 to run a script:
 | 
				
			||||||
 | 
					this runs the script *in* the __main__ namespace.  The latter also
 | 
				
			||||||
 | 
					sets sys.argv[] to the script name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					New in IDLE 0.4 (4/7/99)
 | 
				
			||||||
 | 
					------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Most important change: a new menu entry "File -> Path browser", shows
 | 
				
			||||||
 | 
					a 4-column hierarchical browser which lets you browse sys.path,
 | 
				
			||||||
 | 
					directories, modules, and classes.  Yes, it's a superset of the Class
 | 
				
			||||||
 | 
					browser menu entry.  There's also a new internal module,
 | 
				
			||||||
 | 
					MultiScrolledLists.py, which provides the framework for this dialog.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					New in IDLE 0.3 (2/17/99)
 | 
				
			||||||
 | 
					-------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Most important changes:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Enabled support for running a module, with or without the debugger.
 | 
				
			||||||
 | 
					Output goes to a new window.  Pressing F5 in a module is effectively a
 | 
				
			||||||
 | 
					reload of that module; Control-F5 loads it under the debugger.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Re-enable tearing off the Windows menu, and make a torn-off Windows
 | 
				
			||||||
 | 
					menu update itself whenever a window is opened or closed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Menu items can now be have a checkbox (when the menu label starts
 | 
				
			||||||
 | 
					with "!"); use this for the Debugger and "Auto-open stack viewer"
 | 
				
			||||||
 | 
					(was: JIT stack viewer) menu items.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Added a Quit button to the Debugger API.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The current directory is explicitly inserted into sys.path.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Fix the debugger (when using Python 1.5.2b2) to use canonical
 | 
				
			||||||
 | 
					filenames for breakpoints, so these actually work.  (There's still a
 | 
				
			||||||
 | 
					lot of work to be done to the management of breakpoints in the
 | 
				
			||||||
 | 
					debugger though.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Closing a window that is still colorizing now actually works.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Allow dragging of the separator between the two list boxes in the
 | 
				
			||||||
 | 
					class browser.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Bind ESC to "close window" of the debugger, stack viewer and class
 | 
				
			||||||
 | 
					browser.  It removes the selection highlighting in regular text
 | 
				
			||||||
 | 
					windows.  (These are standard Windows conventions.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					----------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					New in IDLE 0.2 (1/8/99)
 | 
				
			||||||
 | 
					------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Lots of changes; here are the highlights:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					General:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- You can now write and configure your own IDLE extension modules; see
 | 
				
			||||||
 | 
					extend.txt.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					File menu:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The command to open the Python shell window is now in the File menu.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Edit menu:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					New Find dialog with more options; replace dialog; find in files dialog.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Commands to tabify or untabify a region.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Command to format a paragraph.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Debug menu:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					JIT (Just-In-Time) stack viewer toggle -- if set, the stack viewer
 | 
				
			||||||
 | 
					automaticall pops up when you get a traceback.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Windows menu:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Zoom height -- make the window full height.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Help menu:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The help text now show up in a regular window so you can search and
 | 
				
			||||||
 | 
					even edit it if you like.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					----------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IDLE 0.1 was distributed with the Python 1.5.2b1 release on 12/22/98.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					======================================================================
 | 
				
			||||||
							
								
								
									
										151
									
								
								Lib/idlelib/ObjectBrowser.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								Lib/idlelib/ObjectBrowser.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,151 @@
 | 
				
			||||||
 | 
					# XXX TO DO:
 | 
				
			||||||
 | 
					# - popup menu
 | 
				
			||||||
 | 
					# - support partial or total redisplay
 | 
				
			||||||
 | 
					# - more doc strings
 | 
				
			||||||
 | 
					# - tooltips
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# object browser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# XXX TO DO:
 | 
				
			||||||
 | 
					# - for classes/modules, add "open source" to object browser
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from TreeWidget import TreeItem, TreeNode, ScrolledCanvas
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from repr import Repr
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					myrepr = Repr()
 | 
				
			||||||
 | 
					myrepr.maxstring = 100
 | 
				
			||||||
 | 
					myrepr.maxother = 100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ObjectTreeItem(TreeItem):
 | 
				
			||||||
 | 
					    def __init__(self, labeltext, object, setfunction=None):
 | 
				
			||||||
 | 
					        self.labeltext = labeltext
 | 
				
			||||||
 | 
					        self.object = object
 | 
				
			||||||
 | 
					        self.setfunction = setfunction
 | 
				
			||||||
 | 
					    def GetLabelText(self):
 | 
				
			||||||
 | 
					        return self.labeltext
 | 
				
			||||||
 | 
					    def GetText(self):
 | 
				
			||||||
 | 
					        return myrepr.repr(self.object)
 | 
				
			||||||
 | 
					    def GetIconName(self):
 | 
				
			||||||
 | 
					        if not self.IsExpandable():
 | 
				
			||||||
 | 
					            return "python"
 | 
				
			||||||
 | 
					    def IsEditable(self):
 | 
				
			||||||
 | 
					        return self.setfunction is not None
 | 
				
			||||||
 | 
					    def SetText(self, text):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            value = eval(text)
 | 
				
			||||||
 | 
					            self.setfunction(value)
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.object = value
 | 
				
			||||||
 | 
					    def IsExpandable(self):
 | 
				
			||||||
 | 
					        return not not dir(self.object)
 | 
				
			||||||
 | 
					    def GetSubList(self):
 | 
				
			||||||
 | 
					        keys = dir(self.object)
 | 
				
			||||||
 | 
					        sublist = []
 | 
				
			||||||
 | 
					        for key in keys:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                value = getattr(self.object, key)
 | 
				
			||||||
 | 
					            except AttributeError:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            item = make_objecttreeitem(
 | 
				
			||||||
 | 
					                str(key) + " =",
 | 
				
			||||||
 | 
					                value,
 | 
				
			||||||
 | 
					                lambda value, key=key, object=self.object:
 | 
				
			||||||
 | 
					                    setattr(object, key, value))
 | 
				
			||||||
 | 
					            sublist.append(item)
 | 
				
			||||||
 | 
					        return sublist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InstanceTreeItem(ObjectTreeItem):
 | 
				
			||||||
 | 
					    def IsExpandable(self):
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					    def GetSubList(self):
 | 
				
			||||||
 | 
					        sublist = ObjectTreeItem.GetSubList(self)
 | 
				
			||||||
 | 
					        sublist.insert(0,
 | 
				
			||||||
 | 
					            make_objecttreeitem("__class__ =", self.object.__class__))
 | 
				
			||||||
 | 
					        return sublist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ClassTreeItem(ObjectTreeItem):
 | 
				
			||||||
 | 
					    def IsExpandable(self):
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					    def GetSubList(self):
 | 
				
			||||||
 | 
					        sublist = ObjectTreeItem.GetSubList(self)
 | 
				
			||||||
 | 
					        if len(self.object.__bases__) == 1:
 | 
				
			||||||
 | 
					            item = make_objecttreeitem("__bases__[0] =",
 | 
				
			||||||
 | 
					                self.object.__bases__[0])
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            item = make_objecttreeitem("__bases__ =", self.object.__bases__)
 | 
				
			||||||
 | 
					        sublist.insert(0, item)
 | 
				
			||||||
 | 
					        return sublist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class AtomicObjectTreeItem(ObjectTreeItem):
 | 
				
			||||||
 | 
					    def IsExpandable(self):
 | 
				
			||||||
 | 
					        return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SequenceTreeItem(ObjectTreeItem):
 | 
				
			||||||
 | 
					    def IsExpandable(self):
 | 
				
			||||||
 | 
					        return len(self.object) > 0
 | 
				
			||||||
 | 
					    def keys(self):
 | 
				
			||||||
 | 
					        return range(len(self.object))
 | 
				
			||||||
 | 
					    def GetSubList(self):
 | 
				
			||||||
 | 
					        sublist = []
 | 
				
			||||||
 | 
					        for key in self.keys():
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                value = self.object[key]
 | 
				
			||||||
 | 
					            except KeyError:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            def setfunction(value, key=key, object=self.object):
 | 
				
			||||||
 | 
					                object[key] = value
 | 
				
			||||||
 | 
					            item = make_objecttreeitem(`key` + ":", value, setfunction)
 | 
				
			||||||
 | 
					            sublist.append(item)
 | 
				
			||||||
 | 
					        return sublist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DictTreeItem(SequenceTreeItem):
 | 
				
			||||||
 | 
					    def keys(self):
 | 
				
			||||||
 | 
					        keys = self.object.keys()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            keys.sort()
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        return keys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from types import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dispatch = {
 | 
				
			||||||
 | 
					    IntType: AtomicObjectTreeItem,
 | 
				
			||||||
 | 
					    LongType: AtomicObjectTreeItem,
 | 
				
			||||||
 | 
					    FloatType: AtomicObjectTreeItem,
 | 
				
			||||||
 | 
					    StringType: AtomicObjectTreeItem,
 | 
				
			||||||
 | 
					    TupleType: SequenceTreeItem,
 | 
				
			||||||
 | 
					    ListType: SequenceTreeItem,
 | 
				
			||||||
 | 
					    DictType: DictTreeItem,
 | 
				
			||||||
 | 
					    InstanceType: InstanceTreeItem,
 | 
				
			||||||
 | 
					    ClassType: ClassTreeItem,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def make_objecttreeitem(labeltext, object, setfunction=None):
 | 
				
			||||||
 | 
					    t = type(object)
 | 
				
			||||||
 | 
					    if dispatch.has_key(t):
 | 
				
			||||||
 | 
					        c = dispatch[t]
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        c = ObjectTreeItem
 | 
				
			||||||
 | 
					    return c(labeltext, object, setfunction)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Test script
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test():
 | 
				
			||||||
 | 
					    import sys
 | 
				
			||||||
 | 
					    from Tkinter import Toplevel
 | 
				
			||||||
 | 
					    import PyShell
 | 
				
			||||||
 | 
					    root = Toplevel(PyShell.root)
 | 
				
			||||||
 | 
					    root.configure(bd=0, bg="yellow")
 | 
				
			||||||
 | 
					    root.focus_set()
 | 
				
			||||||
 | 
					    sc = ScrolledCanvas(root, bg="white", highlightthickness=0, takefocus=1)
 | 
				
			||||||
 | 
					    sc.frame.pack(expand=1, fill="both")
 | 
				
			||||||
 | 
					    item = make_objecttreeitem("sys", sys)
 | 
				
			||||||
 | 
					    node = TreeNode(sc.canvas, None, item)
 | 
				
			||||||
 | 
					    node.expand()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    test()
 | 
				
			||||||
							
								
								
									
										276
									
								
								Lib/idlelib/OldStackViewer.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										276
									
								
								Lib/idlelib/OldStackViewer.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,276 @@
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					import linecache
 | 
				
			||||||
 | 
					from repr import Repr
 | 
				
			||||||
 | 
					from WindowList import ListedToplevel
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from ScrolledList import ScrolledList
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class StackBrowser:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, root, flist, stack=None):
 | 
				
			||||||
 | 
					        self.top = top = ListedToplevel(root)
 | 
				
			||||||
 | 
					        top.protocol("WM_DELETE_WINDOW", self.close)
 | 
				
			||||||
 | 
					        top.bind("<Key-Escape>", self.close)
 | 
				
			||||||
 | 
					        top.wm_title("Stack viewer")
 | 
				
			||||||
 | 
					        top.wm_iconname("Stack")
 | 
				
			||||||
 | 
					        # Create help label
 | 
				
			||||||
 | 
					        self.helplabel = Label(top,
 | 
				
			||||||
 | 
					            text="Click once to view variables; twice for source",
 | 
				
			||||||
 | 
					            borderwidth=2, relief="groove")
 | 
				
			||||||
 | 
					        self.helplabel.pack(fill="x")
 | 
				
			||||||
 | 
					        #
 | 
				
			||||||
 | 
					        self.sv = StackViewer(top, flist, self)
 | 
				
			||||||
 | 
					        if stack is None:
 | 
				
			||||||
 | 
					            stack = get_stack()
 | 
				
			||||||
 | 
					        self.sv.load_stack(stack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self, event=None):
 | 
				
			||||||
 | 
					        self.top.destroy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    localsframe = None
 | 
				
			||||||
 | 
					    localsviewer = None
 | 
				
			||||||
 | 
					    localsdict = None
 | 
				
			||||||
 | 
					    globalsframe = None
 | 
				
			||||||
 | 
					    globalsviewer = None
 | 
				
			||||||
 | 
					    globalsdict = None
 | 
				
			||||||
 | 
					    curframe = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_frame(self, (frame, lineno)):
 | 
				
			||||||
 | 
					        if frame is self.curframe:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.curframe = None
 | 
				
			||||||
 | 
					        if frame.f_globals is not self.globalsdict:
 | 
				
			||||||
 | 
					            self.show_globals(frame)
 | 
				
			||||||
 | 
					        self.show_locals(frame)
 | 
				
			||||||
 | 
					        self.curframe = frame
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_globals(self, frame):
 | 
				
			||||||
 | 
					        title = "Global Variables"
 | 
				
			||||||
 | 
					        if frame.f_globals.has_key("__name__"):
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                name = str(frame.f_globals["__name__"]) + ""
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                name = ""
 | 
				
			||||||
 | 
					            if name:
 | 
				
			||||||
 | 
					                title = title + " in module " + name
 | 
				
			||||||
 | 
					        self.globalsdict = None
 | 
				
			||||||
 | 
					        if self.globalsviewer:
 | 
				
			||||||
 | 
					            self.globalsviewer.close()
 | 
				
			||||||
 | 
					        self.globalsviewer = None
 | 
				
			||||||
 | 
					        if not self.globalsframe:
 | 
				
			||||||
 | 
					            self.globalsframe = Frame(self.top)
 | 
				
			||||||
 | 
					        self.globalsdict = frame.f_globals
 | 
				
			||||||
 | 
					        self.globalsviewer = NamespaceViewer(
 | 
				
			||||||
 | 
					            self.globalsframe,
 | 
				
			||||||
 | 
					            title,
 | 
				
			||||||
 | 
					            self.globalsdict)
 | 
				
			||||||
 | 
					        self.globalsframe.pack(fill="both", side="bottom")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_locals(self, frame):
 | 
				
			||||||
 | 
					        self.localsdict = None
 | 
				
			||||||
 | 
					        if self.localsviewer:
 | 
				
			||||||
 | 
					            self.localsviewer.close()
 | 
				
			||||||
 | 
					        self.localsviewer = None
 | 
				
			||||||
 | 
					        if frame.f_locals is not frame.f_globals:
 | 
				
			||||||
 | 
					            title = "Local Variables"
 | 
				
			||||||
 | 
					            code = frame.f_code
 | 
				
			||||||
 | 
					            funcname = code.co_name
 | 
				
			||||||
 | 
					            if funcname not in ("?", "", None):
 | 
				
			||||||
 | 
					                title = title + " in " + funcname
 | 
				
			||||||
 | 
					            if not self.localsframe:
 | 
				
			||||||
 | 
					                self.localsframe = Frame(self.top)
 | 
				
			||||||
 | 
					            self.localsdict = frame.f_locals
 | 
				
			||||||
 | 
					            self.localsviewer = NamespaceViewer(
 | 
				
			||||||
 | 
					                self.localsframe,
 | 
				
			||||||
 | 
					                title,
 | 
				
			||||||
 | 
					                self.localsdict)
 | 
				
			||||||
 | 
					            self.localsframe.pack(fill="both", side="top")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if self.localsframe:
 | 
				
			||||||
 | 
					                self.localsframe.forget()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class StackViewer(ScrolledList):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, master, flist, browser):
 | 
				
			||||||
 | 
					        ScrolledList.__init__(self, master, width=80)
 | 
				
			||||||
 | 
					        self.flist = flist
 | 
				
			||||||
 | 
					        self.browser = browser
 | 
				
			||||||
 | 
					        self.stack = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def load_stack(self, stack, index=None):
 | 
				
			||||||
 | 
					        self.stack = stack
 | 
				
			||||||
 | 
					        self.clear()
 | 
				
			||||||
 | 
					##        if len(stack) > 10:
 | 
				
			||||||
 | 
					##            l["height"] = 10
 | 
				
			||||||
 | 
					##            self.topframe.pack(expand=1)
 | 
				
			||||||
 | 
					##        else:
 | 
				
			||||||
 | 
					##            l["height"] = len(stack)
 | 
				
			||||||
 | 
					##            self.topframe.pack(expand=0)
 | 
				
			||||||
 | 
					        for i in range(len(stack)):
 | 
				
			||||||
 | 
					            frame, lineno = stack[i]
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                modname = frame.f_globals["__name__"]
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                modname = "?"
 | 
				
			||||||
 | 
					            code = frame.f_code
 | 
				
			||||||
 | 
					            filename = code.co_filename
 | 
				
			||||||
 | 
					            funcname = code.co_name
 | 
				
			||||||
 | 
					            sourceline = linecache.getline(filename, lineno)
 | 
				
			||||||
 | 
					            sourceline = string.strip(sourceline)
 | 
				
			||||||
 | 
					            if funcname in ("?", "", None):
 | 
				
			||||||
 | 
					                item = "%s, line %d: %s" % (modname, lineno, sourceline)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                item = "%s.%s(), line %d: %s" % (modname, funcname,
 | 
				
			||||||
 | 
					                                                 lineno, sourceline)
 | 
				
			||||||
 | 
					            if i == index:
 | 
				
			||||||
 | 
					                item = "> " + item
 | 
				
			||||||
 | 
					            self.append(item)
 | 
				
			||||||
 | 
					        if index is not None:
 | 
				
			||||||
 | 
					            self.select(index)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def popup_event(self, event):
 | 
				
			||||||
 | 
					        if self.stack:
 | 
				
			||||||
 | 
					            return ScrolledList.popup_event(self, event)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def fill_menu(self):
 | 
				
			||||||
 | 
					        menu = self.menu
 | 
				
			||||||
 | 
					        menu.add_command(label="Go to source line",
 | 
				
			||||||
 | 
					                         command=self.goto_source_line)
 | 
				
			||||||
 | 
					        menu.add_command(label="Show stack frame",
 | 
				
			||||||
 | 
					                         command=self.show_stack_frame)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_select(self, index):
 | 
				
			||||||
 | 
					        if 0 <= index < len(self.stack):
 | 
				
			||||||
 | 
					            self.browser.show_frame(self.stack[index])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_double(self, index):
 | 
				
			||||||
 | 
					        self.show_source(index)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def goto_source_line(self):
 | 
				
			||||||
 | 
					        index = self.listbox.index("active")
 | 
				
			||||||
 | 
					        self.show_source(index)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_stack_frame(self):
 | 
				
			||||||
 | 
					        index = self.listbox.index("active")
 | 
				
			||||||
 | 
					        if 0 <= index < len(self.stack):
 | 
				
			||||||
 | 
					            self.browser.show_frame(self.stack[index])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_source(self, index):
 | 
				
			||||||
 | 
					        if not (0 <= index < len(self.stack)):
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        frame, lineno = self.stack[index]
 | 
				
			||||||
 | 
					        code = frame.f_code
 | 
				
			||||||
 | 
					        filename = code.co_filename
 | 
				
			||||||
 | 
					        if os.path.isfile(filename):
 | 
				
			||||||
 | 
					            edit = self.flist.open(filename)
 | 
				
			||||||
 | 
					            if edit:
 | 
				
			||||||
 | 
					                edit.gotoline(lineno)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_stack(t=None, f=None):
 | 
				
			||||||
 | 
					    if t is None:
 | 
				
			||||||
 | 
					        t = sys.last_traceback
 | 
				
			||||||
 | 
					    stack = []
 | 
				
			||||||
 | 
					    if t and t.tb_frame is f:
 | 
				
			||||||
 | 
					        t = t.tb_next
 | 
				
			||||||
 | 
					    while f is not None:
 | 
				
			||||||
 | 
					        stack.append((f, f.f_lineno))
 | 
				
			||||||
 | 
					        if f is self.botframe:
 | 
				
			||||||
 | 
					            break
 | 
				
			||||||
 | 
					        f = f.f_back
 | 
				
			||||||
 | 
					    stack.reverse()
 | 
				
			||||||
 | 
					    while t is not None:
 | 
				
			||||||
 | 
					        stack.append((t.tb_frame, t.tb_lineno))
 | 
				
			||||||
 | 
					        t = t.tb_next
 | 
				
			||||||
 | 
					    return stack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def getexception(type=None, value=None):
 | 
				
			||||||
 | 
					    if type is None:
 | 
				
			||||||
 | 
					        type = sys.last_type
 | 
				
			||||||
 | 
					        value = sys.last_value
 | 
				
			||||||
 | 
					    if hasattr(type, "__name__"):
 | 
				
			||||||
 | 
					        type = type.__name__
 | 
				
			||||||
 | 
					    s = str(type)
 | 
				
			||||||
 | 
					    if value is not None:
 | 
				
			||||||
 | 
					        s = s + ": " + str(value)
 | 
				
			||||||
 | 
					    return s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NamespaceViewer:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, master, title, dict=None):
 | 
				
			||||||
 | 
					        width = 0
 | 
				
			||||||
 | 
					        height = 40
 | 
				
			||||||
 | 
					        if dict:
 | 
				
			||||||
 | 
					            height = 20*len(dict) # XXX 20 == observed height of Entry widget
 | 
				
			||||||
 | 
					        self.master = master
 | 
				
			||||||
 | 
					        self.title = title
 | 
				
			||||||
 | 
					        self.repr = Repr()
 | 
				
			||||||
 | 
					        self.repr.maxstring = 60
 | 
				
			||||||
 | 
					        self.repr.maxother = 60
 | 
				
			||||||
 | 
					        self.frame = frame = Frame(master)
 | 
				
			||||||
 | 
					        self.frame.pack(expand=1, fill="both")
 | 
				
			||||||
 | 
					        self.label = Label(frame, text=title, borderwidth=2, relief="groove")
 | 
				
			||||||
 | 
					        self.label.pack(fill="x")
 | 
				
			||||||
 | 
					        self.vbar = vbar = Scrollbar(frame, name="vbar")
 | 
				
			||||||
 | 
					        vbar.pack(side="right", fill="y")
 | 
				
			||||||
 | 
					        self.canvas = canvas = Canvas(frame,
 | 
				
			||||||
 | 
					                                      height=min(300, max(40, height)),
 | 
				
			||||||
 | 
					                                      scrollregion=(0, 0, width, height))
 | 
				
			||||||
 | 
					        canvas.pack(side="left", fill="both", expand=1)
 | 
				
			||||||
 | 
					        vbar["command"] = canvas.yview
 | 
				
			||||||
 | 
					        canvas["yscrollcommand"] = vbar.set
 | 
				
			||||||
 | 
					        self.subframe = subframe = Frame(canvas)
 | 
				
			||||||
 | 
					        self.sfid = canvas.create_window(0, 0, window=subframe, anchor="nw")
 | 
				
			||||||
 | 
					        self.load_dict(dict)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    dict = -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def load_dict(self, dict, force=0):
 | 
				
			||||||
 | 
					        if dict is self.dict and not force:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        subframe = self.subframe
 | 
				
			||||||
 | 
					        frame = self.frame
 | 
				
			||||||
 | 
					        for c in subframe.children.values():
 | 
				
			||||||
 | 
					            c.destroy()
 | 
				
			||||||
 | 
					        self.dict = None
 | 
				
			||||||
 | 
					        if not dict:
 | 
				
			||||||
 | 
					            l = Label(subframe, text="None")
 | 
				
			||||||
 | 
					            l.grid(row=0, column=0)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            names = dict.keys()
 | 
				
			||||||
 | 
					            names.sort()
 | 
				
			||||||
 | 
					            row = 0
 | 
				
			||||||
 | 
					            for name in names:
 | 
				
			||||||
 | 
					                value = dict[name]
 | 
				
			||||||
 | 
					                svalue = self.repr.repr(value) # repr(value)
 | 
				
			||||||
 | 
					                l = Label(subframe, text=name)
 | 
				
			||||||
 | 
					                l.grid(row=row, column=0, sticky="nw")
 | 
				
			||||||
 | 
					    ##            l = Label(subframe, text=svalue, justify="l", wraplength=300)
 | 
				
			||||||
 | 
					                l = Entry(subframe, width=0, borderwidth=0)
 | 
				
			||||||
 | 
					                l.insert(0, svalue)
 | 
				
			||||||
 | 
					    ##            l["state"] = "disabled"
 | 
				
			||||||
 | 
					                l.grid(row=row, column=1, sticky="nw")
 | 
				
			||||||
 | 
					                row = row+1
 | 
				
			||||||
 | 
					        self.dict = dict
 | 
				
			||||||
 | 
					        # XXX Could we use a <Configure> callback for the following?
 | 
				
			||||||
 | 
					        subframe.update_idletasks() # Alas!
 | 
				
			||||||
 | 
					        width = subframe.winfo_reqwidth()
 | 
				
			||||||
 | 
					        height = subframe.winfo_reqheight()
 | 
				
			||||||
 | 
					        canvas = self.canvas
 | 
				
			||||||
 | 
					        self.canvas["scrollregion"] = (0, 0, width, height)
 | 
				
			||||||
 | 
					        if height > 300:
 | 
				
			||||||
 | 
					            canvas["height"] = 300
 | 
				
			||||||
 | 
					            frame.pack(expand=1)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            canvas["height"] = height
 | 
				
			||||||
 | 
					            frame.pack(expand=0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self):
 | 
				
			||||||
 | 
					        self.frame.destroy()
 | 
				
			||||||
							
								
								
									
										279
									
								
								Lib/idlelib/OutputWindow.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										279
									
								
								Lib/idlelib/OutputWindow.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,279 @@
 | 
				
			||||||
 | 
					# changes by dscherer@cmu.edu
 | 
				
			||||||
 | 
					#   - OutputWindow and OnDemandOutputWindow have been hastily
 | 
				
			||||||
 | 
					#     extended to provide readline() support, an "iomark" separate
 | 
				
			||||||
 | 
					#     from the "insert" cursor, and scrolling to clear the window.
 | 
				
			||||||
 | 
					#     These changes are used by the ExecBinding module to provide
 | 
				
			||||||
 | 
					#     standard input and output for user programs.  Many of the new
 | 
				
			||||||
 | 
					#     features are very similar to features of PyShell, which is a
 | 
				
			||||||
 | 
					#     subclass of OutputWindow.  Someone should make some sense of
 | 
				
			||||||
 | 
					#     this.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					from EditorWindow import EditorWindow
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import tkMessageBox
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from UndoDelegator import UndoDelegator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class OutputUndoDelegator(UndoDelegator):
 | 
				
			||||||
 | 
					    reading = 0
 | 
				
			||||||
 | 
					    # Forbid insert/delete before the I/O mark, in the blank lines after
 | 
				
			||||||
 | 
					    #   the output, or *anywhere* if we are not presently doing user input
 | 
				
			||||||
 | 
					    def insert(self, index, chars, tags=None):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            if (self.delegate.compare(index, "<", "iomark") or
 | 
				
			||||||
 | 
					                self.delegate.compare(index, ">", "endmark") or
 | 
				
			||||||
 | 
					                (index!="iomark" and not self.reading)):
 | 
				
			||||||
 | 
					                self.delegate.bell()
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					        except TclError:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        UndoDelegator.insert(self, index, chars, tags)
 | 
				
			||||||
 | 
					    def delete(self, index1, index2=None):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            if (self.delegate.compare(index1, "<", "iomark") or
 | 
				
			||||||
 | 
					                self.delegate.compare(index1, ">", "endmark") or
 | 
				
			||||||
 | 
					                (index2 and self.delegate.compare(index2, ">=", "endmark")) or
 | 
				
			||||||
 | 
					                not self.reading):
 | 
				
			||||||
 | 
					                self.delegate.bell()
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					        except TclError:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        UndoDelegator.delete(self, index1, index2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class OutputWindow(EditorWindow):
 | 
				
			||||||
 | 
					    """An editor window that can serve as an input and output file.
 | 
				
			||||||
 | 
					       The input support has been rather hastily hacked in, and should
 | 
				
			||||||
 | 
					       not be trusted.
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    UndoDelegator = OutputUndoDelegator
 | 
				
			||||||
 | 
					    source_window = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, *args, **keywords):
 | 
				
			||||||
 | 
					        if keywords.has_key('source_window'):
 | 
				
			||||||
 | 
					            self.source_window = keywords['source_window']
 | 
				
			||||||
 | 
					        apply(EditorWindow.__init__, (self,) + args)
 | 
				
			||||||
 | 
					        self.text.bind("<<goto-file-line>>", self.goto_file_line)
 | 
				
			||||||
 | 
					        self.text.bind("<<newline-and-indent>>", self.enter_callback)
 | 
				
			||||||
 | 
					        self.text.mark_set("iomark","1.0")
 | 
				
			||||||
 | 
					        self.text.mark_gravity("iomark", LEFT)
 | 
				
			||||||
 | 
					        self.text.mark_set("endmark","1.0")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Customize EditorWindow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ispythonsource(self, filename):
 | 
				
			||||||
 | 
					        # No colorization needed
 | 
				
			||||||
 | 
					        return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def short_title(self):
 | 
				
			||||||
 | 
					        return "Output"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def long_title(self):
 | 
				
			||||||
 | 
					        return ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def maybesave(self):
 | 
				
			||||||
 | 
					        # Override base class method -- don't ask any questions
 | 
				
			||||||
 | 
					        if self.get_saved():
 | 
				
			||||||
 | 
					            return "yes"
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return "no"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Act as input file - incomplete
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_line_and_column(self, event=None):
 | 
				
			||||||
 | 
					        index = self.text.index(INSERT)
 | 
				
			||||||
 | 
					        if (self.text.compare(index, ">", "endmark")):
 | 
				
			||||||
 | 
					          self.text.mark_set("insert", "endmark")
 | 
				
			||||||
 | 
					        self.text.see("insert")
 | 
				
			||||||
 | 
					        EditorWindow.set_line_and_column(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    reading = 0
 | 
				
			||||||
 | 
					    canceled = 0
 | 
				
			||||||
 | 
					    endoffile = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def readline(self):
 | 
				
			||||||
 | 
					        save = self.reading
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.reading = self.undo.reading = 1
 | 
				
			||||||
 | 
					            self.text.mark_set("insert", "iomark")
 | 
				
			||||||
 | 
					            self.text.see("insert")
 | 
				
			||||||
 | 
					            self.top.mainloop()
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            self.reading = self.undo.reading = save
 | 
				
			||||||
 | 
					        line = self.text.get("input", "iomark")
 | 
				
			||||||
 | 
					        if self.canceled:
 | 
				
			||||||
 | 
					            self.canceled = 0
 | 
				
			||||||
 | 
					            raise KeyboardInterrupt
 | 
				
			||||||
 | 
					        if self.endoffile:
 | 
				
			||||||
 | 
					            self.endoffile = 0
 | 
				
			||||||
 | 
					            return ""
 | 
				
			||||||
 | 
					        return line or '\n'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self):
 | 
				
			||||||
 | 
					        self.interrupt()
 | 
				
			||||||
 | 
					        return EditorWindow.close(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def interrupt(self):
 | 
				
			||||||
 | 
					        if self.reading:
 | 
				
			||||||
 | 
					            self.endoffile = 1
 | 
				
			||||||
 | 
					            self.top.quit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def enter_callback(self, event):
 | 
				
			||||||
 | 
					        if self.reading and self.text.compare("insert", ">=", "iomark"):
 | 
				
			||||||
 | 
					            self.text.mark_set("input", "iomark")
 | 
				
			||||||
 | 
					            self.text.mark_set("iomark", "insert")
 | 
				
			||||||
 | 
					            self.write('\n',"iomark")
 | 
				
			||||||
 | 
					            self.text.tag_add("stdin", "input", "iomark")
 | 
				
			||||||
 | 
					            self.text.update_idletasks()
 | 
				
			||||||
 | 
					            self.top.quit() # Break out of recursive mainloop() in raw_input()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Act as output file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def write(self, s, tags=(), mark="iomark"):
 | 
				
			||||||
 | 
					        self.text.mark_gravity(mark, RIGHT)
 | 
				
			||||||
 | 
					        self.text.insert(mark, str(s), tags)
 | 
				
			||||||
 | 
					        self.text.mark_gravity(mark, LEFT)
 | 
				
			||||||
 | 
					        self.text.see(mark)
 | 
				
			||||||
 | 
					        self.text.update()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def writelines(self, l):
 | 
				
			||||||
 | 
					        map(self.write, l)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def flush(self):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Our own right-button menu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rmenu_specs = [
 | 
				
			||||||
 | 
					        ("Go to file/line", "<<goto-file-line>>"),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    file_line_pats = [
 | 
				
			||||||
 | 
					        r'file "([^"]*)", line (\d+)',
 | 
				
			||||||
 | 
					        r'([^\s]+)\((\d+)\)',
 | 
				
			||||||
 | 
					        r'([^\s]+):\s*(\d+):',
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    file_line_progs = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def goto_file_line(self, event=None):
 | 
				
			||||||
 | 
					        if self.file_line_progs is None:
 | 
				
			||||||
 | 
					            l = []
 | 
				
			||||||
 | 
					            for pat in self.file_line_pats:
 | 
				
			||||||
 | 
					                l.append(re.compile(pat, re.IGNORECASE))
 | 
				
			||||||
 | 
					            self.file_line_progs = l
 | 
				
			||||||
 | 
					        # x, y = self.event.x, self.event.y
 | 
				
			||||||
 | 
					        # self.text.mark_set("insert", "@%d,%d" % (x, y))
 | 
				
			||||||
 | 
					        line = self.text.get("insert linestart", "insert lineend")
 | 
				
			||||||
 | 
					        result = self._file_line_helper(line)
 | 
				
			||||||
 | 
					        if not result:
 | 
				
			||||||
 | 
					            # Try the previous line.  This is handy e.g. in tracebacks,
 | 
				
			||||||
 | 
					            # where you tend to right-click on the displayed source line
 | 
				
			||||||
 | 
					            line = self.text.get("insert -1line linestart",
 | 
				
			||||||
 | 
					                                 "insert -1line lineend")
 | 
				
			||||||
 | 
					            result = self._file_line_helper(line)
 | 
				
			||||||
 | 
					            if not result:
 | 
				
			||||||
 | 
					                tkMessageBox.showerror(
 | 
				
			||||||
 | 
					                    "No special line",
 | 
				
			||||||
 | 
					                    "The line you point at doesn't look like "
 | 
				
			||||||
 | 
					                    "a valid file name followed by a line number.",
 | 
				
			||||||
 | 
					                    master=self.text)
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					        filename, lineno = result
 | 
				
			||||||
 | 
					        edit = self.untitled(filename) or self.flist.open(filename)
 | 
				
			||||||
 | 
					        edit.gotoline(lineno)
 | 
				
			||||||
 | 
					        edit.wakeup()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def untitled(self, filename):
 | 
				
			||||||
 | 
					        if filename!='Untitled' or not self.source_window or self.source_window.io.filename:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        return self.source_window
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _file_line_helper(self, line):
 | 
				
			||||||
 | 
					        for prog in self.file_line_progs:
 | 
				
			||||||
 | 
					            m = prog.search(line)
 | 
				
			||||||
 | 
					            if m:
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        filename, lineno = m.group(1, 2)
 | 
				
			||||||
 | 
					        if not self.untitled(filename):
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                f = open(filename, "r")
 | 
				
			||||||
 | 
					                f.close()
 | 
				
			||||||
 | 
					            except IOError:
 | 
				
			||||||
 | 
					                return None
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            return filename, int(lineno)
 | 
				
			||||||
 | 
					        except TypeError:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# This classes now used by ExecBinding.py:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class OnDemandOutputWindow:
 | 
				
			||||||
 | 
					    source_window = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tagdefs = {
 | 
				
			||||||
 | 
					        # XXX Should use IdlePrefs.ColorPrefs
 | 
				
			||||||
 | 
					        "stdin":   {"foreground": "black"},
 | 
				
			||||||
 | 
					        "stdout":  {"foreground": "blue"},
 | 
				
			||||||
 | 
					        "stderr":  {"foreground": "red"},
 | 
				
			||||||
 | 
					    }   
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def __init__(self, flist):
 | 
				
			||||||
 | 
					        self.flist = flist
 | 
				
			||||||
 | 
					        self.owin = None
 | 
				
			||||||
 | 
					        self.title = "Output"
 | 
				
			||||||
 | 
					        self.close_hook = None
 | 
				
			||||||
 | 
					        self.old_close = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def owclose(self):
 | 
				
			||||||
 | 
					        if self.close_hook:
 | 
				
			||||||
 | 
					            self.close_hook()
 | 
				
			||||||
 | 
					        if self.old_close:
 | 
				
			||||||
 | 
					            self.old_close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_title(self, title):
 | 
				
			||||||
 | 
					        self.title = title
 | 
				
			||||||
 | 
					        if self.owin and self.owin.text:
 | 
				
			||||||
 | 
					          self.owin.saved_change_hook()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def write(self, s, tags=(), mark="iomark"):
 | 
				
			||||||
 | 
					        if not self.owin or not self.owin.text:
 | 
				
			||||||
 | 
					            self.setup()
 | 
				
			||||||
 | 
					        self.owin.write(s, tags, mark)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def readline(self):
 | 
				
			||||||
 | 
					        if not self.owin or not self.owin.text:
 | 
				
			||||||
 | 
					            self.setup()
 | 
				
			||||||
 | 
					        return self.owin.readline()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def scroll_clear(self):
 | 
				
			||||||
 | 
					        if self.owin and self.owin.text:
 | 
				
			||||||
 | 
					           lineno = self.owin.getlineno("endmark")
 | 
				
			||||||
 | 
					           self.owin.text.mark_set("insert","endmark")
 | 
				
			||||||
 | 
					           self.owin.text.yview(float(lineno))
 | 
				
			||||||
 | 
					           self.owin.wakeup()
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def setup(self):
 | 
				
			||||||
 | 
					        self.owin = owin = OutputWindow(self.flist, source_window = self.source_window)
 | 
				
			||||||
 | 
					        owin.short_title = lambda self=self: self.title
 | 
				
			||||||
 | 
					        text = owin.text
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.old_close = owin.close_hook
 | 
				
			||||||
 | 
					        owin.close_hook = self.owclose
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # xxx Bad hack: 50 blank lines at the bottom so that
 | 
				
			||||||
 | 
					        #     we can scroll the top of the window to the output
 | 
				
			||||||
 | 
					        #     cursor in scroll_clear().  There must be a better way...
 | 
				
			||||||
 | 
					        owin.text.mark_gravity('endmark', LEFT)
 | 
				
			||||||
 | 
					        owin.text.insert('iomark', '\n'*50)
 | 
				
			||||||
 | 
					        owin.text.mark_gravity('endmark', RIGHT)
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        for tag, cnf in self.tagdefs.items():
 | 
				
			||||||
 | 
					            if cnf:
 | 
				
			||||||
 | 
					                apply(text.tag_configure, (tag,), cnf)
 | 
				
			||||||
 | 
					        text.tag_raise('sel')
 | 
				
			||||||
							
								
								
									
										192
									
								
								Lib/idlelib/ParenMatch.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										192
									
								
								Lib/idlelib/ParenMatch.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,192 @@
 | 
				
			||||||
 | 
					"""ParenMatch -- An IDLE extension for parenthesis matching.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When you hit a right paren, the cursor should move briefly to the left
 | 
				
			||||||
 | 
					paren.  Paren here is used generically; the matching applies to
 | 
				
			||||||
 | 
					parentheses, square brackets, and curly braces.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					WARNING: This extension will fight with the CallTips extension,
 | 
				
			||||||
 | 
					because they both are interested in the KeyRelease-parenright event.
 | 
				
			||||||
 | 
					We'll have to fix IDLE to do something reasonable when two or more
 | 
				
			||||||
 | 
					extensions what to capture the same event.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import PyParse
 | 
				
			||||||
 | 
					from AutoIndent import AutoIndent, index2line
 | 
				
			||||||
 | 
					from IdleConf import idleconf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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:
 | 
				
			||||||
 | 
					        - fix interaction with CallTips
 | 
				
			||||||
 | 
					        - 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 = []
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    keydefs = {
 | 
				
			||||||
 | 
					        '<<flash-open-paren>>' : ('<KeyRelease-parenright>',
 | 
				
			||||||
 | 
					                                  '<KeyRelease-bracketright>',
 | 
				
			||||||
 | 
					                                  '<KeyRelease-braceright>'),
 | 
				
			||||||
 | 
					        '<<check-restore>>' : ('<KeyPress>',),
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    windows_keydefs = {}
 | 
				
			||||||
 | 
					    unix_keydefs = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    iconf = idleconf.getsection('ParenMatch')
 | 
				
			||||||
 | 
					    STYLE = iconf.getdef('style', 'default')
 | 
				
			||||||
 | 
					    FLASH_DELAY = iconf.getint('flash-delay')
 | 
				
			||||||
 | 
					    HILITE_CONFIG = iconf.getcolor('hilite')
 | 
				
			||||||
 | 
					    BELL = iconf.getboolean('bell')
 | 
				
			||||||
 | 
					    del iconf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, editwin):
 | 
				
			||||||
 | 
					        self.editwin = editwin
 | 
				
			||||||
 | 
					        self.text = editwin.text
 | 
				
			||||||
 | 
					        self.finder = LastOpenBracketFinder(editwin)
 | 
				
			||||||
 | 
					        self.counter = 0
 | 
				
			||||||
 | 
					        self._restore = None
 | 
				
			||||||
 | 
					        self.set_style(self.STYLE)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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_open_paren_event(self, event):
 | 
				
			||||||
 | 
					        index = self.finder.find(keysym_type(event.keysym))
 | 
				
			||||||
 | 
					        if index is None:
 | 
				
			||||||
 | 
					            self.warn_mismatched()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self._restore = 1
 | 
				
			||||||
 | 
					        self.create_tag(index)
 | 
				
			||||||
 | 
					        self.set_timeout()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def check_restore_event(self, event=None):
 | 
				
			||||||
 | 
					        if self._restore:
 | 
				
			||||||
 | 
					            self.text.tag_delete("paren")
 | 
				
			||||||
 | 
					            self._restore = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def handle_restore_timer(self, timer_count):
 | 
				
			||||||
 | 
					        if timer_count + 1 == self.counter:
 | 
				
			||||||
 | 
					            self.check_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, index):
 | 
				
			||||||
 | 
					        """Highlight the single paren that matches"""
 | 
				
			||||||
 | 
					        self.text.tag_add("paren", index)
 | 
				
			||||||
 | 
					        self.text.tag_config("paren", self.HILITE_CONFIG)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_tag_expression(self, index):
 | 
				
			||||||
 | 
					        """Highlight the entire expression"""
 | 
				
			||||||
 | 
					        self.text.tag_add("paren", index, "insert")
 | 
				
			||||||
 | 
					        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"""
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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.editwin.text_frame.after(self.FLASH_DELAY,
 | 
				
			||||||
 | 
					                                      lambda self=self, c=self.counter: \
 | 
				
			||||||
 | 
					                                      self.handle_restore_timer(c))
 | 
				
			||||||
 | 
					        self.counter = self.counter + 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def keysym_type(ks):
 | 
				
			||||||
 | 
					    # Not all possible chars or keysyms are checked because of the
 | 
				
			||||||
 | 
					    # limited context in which the function is used.
 | 
				
			||||||
 | 
					    if ks == "parenright" or ks == "(":
 | 
				
			||||||
 | 
					        return "paren"
 | 
				
			||||||
 | 
					    if ks == "bracketright" or ks == "[":
 | 
				
			||||||
 | 
					        return "bracket"
 | 
				
			||||||
 | 
					    if ks == "braceright" or ks == "{":
 | 
				
			||||||
 | 
					        return "brace"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class LastOpenBracketFinder:
 | 
				
			||||||
 | 
					    num_context_lines = AutoIndent.num_context_lines
 | 
				
			||||||
 | 
					    indentwidth = AutoIndent.indentwidth
 | 
				
			||||||
 | 
					    tabwidth = AutoIndent.tabwidth
 | 
				
			||||||
 | 
					    context_use_ps1 = AutoIndent.context_use_ps1
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def __init__(self, editwin):
 | 
				
			||||||
 | 
					        self.editwin = editwin
 | 
				
			||||||
 | 
					        self.text = editwin.text
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _find_offset_in_buf(self, lno):
 | 
				
			||||||
 | 
					        y = PyParse.Parser(self.indentwidth, self.tabwidth)
 | 
				
			||||||
 | 
					        for context in self.num_context_lines:
 | 
				
			||||||
 | 
					            startat = max(lno - context, 1)
 | 
				
			||||||
 | 
					            startatindex = `startat` + ".0"
 | 
				
			||||||
 | 
					            # rawtext needs to contain everything up to the last
 | 
				
			||||||
 | 
					            # character, which was the close paren.  the parser also
 | 
				
			||||||
 | 
						    # requires that the last line ends with "\n"
 | 
				
			||||||
 | 
					            rawtext = self.text.get(startatindex, "insert")[:-1] + "\n"
 | 
				
			||||||
 | 
					            y.set_str(rawtext)
 | 
				
			||||||
 | 
					            bod = y.find_good_parse_start(
 | 
				
			||||||
 | 
					                        self.context_use_ps1,
 | 
				
			||||||
 | 
					                        self._build_char_in_string_func(startatindex))
 | 
				
			||||||
 | 
					            if bod is not None or startat == 1:
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					        y.set_lo(bod or 0)
 | 
				
			||||||
 | 
					        i = y.get_last_open_bracket_pos()
 | 
				
			||||||
 | 
					        return i, y.str
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def find(self, right_keysym_type):
 | 
				
			||||||
 | 
					        """Return the location of the last open paren"""
 | 
				
			||||||
 | 
					        lno = index2line(self.text.index("insert"))
 | 
				
			||||||
 | 
					        i, buf = self._find_offset_in_buf(lno)
 | 
				
			||||||
 | 
					        if i is None \
 | 
				
			||||||
 | 
						   or keysym_type(buf[i]) != right_keysym_type:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        lines_back = string.count(buf[i:], "\n") - 1
 | 
				
			||||||
 | 
					        # subtract one for the "\n" added to please the parser
 | 
				
			||||||
 | 
					        upto_open = buf[:i]
 | 
				
			||||||
 | 
					        j = string.rfind(upto_open, "\n") + 1 # offset of column 0 of line
 | 
				
			||||||
 | 
					        offset = i - j
 | 
				
			||||||
 | 
					        return "%d.%d" % (lno - lines_back, offset)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _build_char_in_string_func(self, startindex):
 | 
				
			||||||
 | 
					        def inner(offset, startindex=startindex,
 | 
				
			||||||
 | 
					                  icis=self.editwin.is_char_in_string):
 | 
				
			||||||
 | 
					            return icis(startindex + "%dc" % offset)
 | 
				
			||||||
 | 
					        return inner
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										95
									
								
								Lib/idlelib/PathBrowser.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								Lib/idlelib/PathBrowser.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,95 @@
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import imp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from TreeWidget import TreeItem
 | 
				
			||||||
 | 
					from ClassBrowser import ClassBrowser, ModuleBrowserTreeItem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PathBrowser(ClassBrowser):
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def __init__(self, flist):
 | 
				
			||||||
 | 
					        self.init(flist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def settitle(self):
 | 
				
			||||||
 | 
					        self.top.wm_title("Path Browser")
 | 
				
			||||||
 | 
					        self.top.wm_iconname("Path Browser")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def rootnode(self):
 | 
				
			||||||
 | 
					        return PathBrowserTreeItem()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PathBrowserTreeItem(TreeItem):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetText(self):
 | 
				
			||||||
 | 
					        return "sys.path"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetSubList(self):
 | 
				
			||||||
 | 
					        sublist = []
 | 
				
			||||||
 | 
					        for dir in sys.path:
 | 
				
			||||||
 | 
					            item = DirBrowserTreeItem(dir)
 | 
				
			||||||
 | 
					            sublist.append(item)
 | 
				
			||||||
 | 
					        return sublist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DirBrowserTreeItem(TreeItem):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, dir, packages=[]):
 | 
				
			||||||
 | 
					        self.dir = dir
 | 
				
			||||||
 | 
					        self.packages = packages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetText(self):
 | 
				
			||||||
 | 
					        if not self.packages:
 | 
				
			||||||
 | 
					            return self.dir
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return self.packages[-1] + ": package"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetSubList(self):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            names = os.listdir(self.dir or os.curdir)
 | 
				
			||||||
 | 
					        except os.error:
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					        packages = []
 | 
				
			||||||
 | 
					        for name in names:
 | 
				
			||||||
 | 
					            file = os.path.join(self.dir, name)
 | 
				
			||||||
 | 
					            if self.ispackagedir(file):
 | 
				
			||||||
 | 
					                nn = os.path.normcase(name)
 | 
				
			||||||
 | 
					                packages.append((nn, name, file))
 | 
				
			||||||
 | 
					        packages.sort()
 | 
				
			||||||
 | 
					        sublist = []
 | 
				
			||||||
 | 
					        for nn, name, file in packages:
 | 
				
			||||||
 | 
					            item = DirBrowserTreeItem(file, self.packages + [name])
 | 
				
			||||||
 | 
					            sublist.append(item)
 | 
				
			||||||
 | 
					        for nn, name in self.listmodules(names):
 | 
				
			||||||
 | 
					            item = ModuleBrowserTreeItem(os.path.join(self.dir, name))
 | 
				
			||||||
 | 
					            sublist.append(item)
 | 
				
			||||||
 | 
					        return sublist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ispackagedir(self, file):
 | 
				
			||||||
 | 
					        if not os.path.isdir(file):
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        init = os.path.join(file, "__init__.py")
 | 
				
			||||||
 | 
					        return os.path.exists(init)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def listmodules(self, allnames):
 | 
				
			||||||
 | 
					        modules = {}
 | 
				
			||||||
 | 
					        suffixes = imp.get_suffixes()
 | 
				
			||||||
 | 
					        sorted = []
 | 
				
			||||||
 | 
					        for suff, mode, flag in suffixes:
 | 
				
			||||||
 | 
					            i = -len(suff)
 | 
				
			||||||
 | 
					            for name in allnames[:]:
 | 
				
			||||||
 | 
					                normed_name = os.path.normcase(name)
 | 
				
			||||||
 | 
					                if normed_name[i:] == suff:
 | 
				
			||||||
 | 
					                    mod_name = name[:i]
 | 
				
			||||||
 | 
					                    if not modules.has_key(mod_name):
 | 
				
			||||||
 | 
					                        modules[mod_name] = None
 | 
				
			||||||
 | 
					                        sorted.append((normed_name, name))
 | 
				
			||||||
 | 
					                        allnames.remove(name)
 | 
				
			||||||
 | 
					        sorted.sort()
 | 
				
			||||||
 | 
					        return sorted
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    import PyShell
 | 
				
			||||||
 | 
					    PathBrowser(PyShell.flist)
 | 
				
			||||||
 | 
					    if sys.stdin is sys.__stdin__:
 | 
				
			||||||
 | 
					        mainloop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										85
									
								
								Lib/idlelib/Percolator.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								Lib/idlelib/Percolator.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,85 @@
 | 
				
			||||||
 | 
					from WidgetRedirector import WidgetRedirector
 | 
				
			||||||
 | 
					from Delegator import Delegator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Percolator:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, text):
 | 
				
			||||||
 | 
					        # XXX would be nice to inherit from Delegator
 | 
				
			||||||
 | 
					        self.text = text
 | 
				
			||||||
 | 
					        self.redir = WidgetRedirector(text)
 | 
				
			||||||
 | 
					        self.top = self.bottom = Delegator(text)
 | 
				
			||||||
 | 
					        self.bottom.insert = self.redir.register("insert", self.insert)
 | 
				
			||||||
 | 
					        self.bottom.delete = self.redir.register("delete", self.delete)
 | 
				
			||||||
 | 
					        self.filters = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self):
 | 
				
			||||||
 | 
					        while self.top is not self.bottom:
 | 
				
			||||||
 | 
					            self.removefilter(self.top)
 | 
				
			||||||
 | 
					        self.top = None
 | 
				
			||||||
 | 
					        self.bottom.setdelegate(None); self.bottom = None
 | 
				
			||||||
 | 
					        self.redir.close(); self.redir = None
 | 
				
			||||||
 | 
					        self.text = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def insert(self, index, chars, tags=None):
 | 
				
			||||||
 | 
					        # Could go away if inheriting from Delegator
 | 
				
			||||||
 | 
					        self.top.insert(index, chars, tags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete(self, index1, index2=None):
 | 
				
			||||||
 | 
					        # Could go away if inheriting from Delegator
 | 
				
			||||||
 | 
					        self.top.delete(index1, index2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def insertfilter(self, filter):
 | 
				
			||||||
 | 
					        # Perhaps rename to pushfilter()?
 | 
				
			||||||
 | 
					        assert isinstance(filter, Delegator)
 | 
				
			||||||
 | 
					        assert filter.delegate is None
 | 
				
			||||||
 | 
					        filter.setdelegate(self.top)
 | 
				
			||||||
 | 
					        self.top = filter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def removefilter(self, filter):
 | 
				
			||||||
 | 
					        # XXX Perhaps should only support popfilter()?
 | 
				
			||||||
 | 
					        assert isinstance(filter, Delegator)
 | 
				
			||||||
 | 
					        assert filter.delegate is not None
 | 
				
			||||||
 | 
					        f = self.top
 | 
				
			||||||
 | 
					        if f is filter:
 | 
				
			||||||
 | 
					            self.top = filter.delegate
 | 
				
			||||||
 | 
					            filter.setdelegate(None)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            while f.delegate is not filter:
 | 
				
			||||||
 | 
					                assert f is not self.bottom
 | 
				
			||||||
 | 
					                f.resetcache()
 | 
				
			||||||
 | 
					                f = f.delegate
 | 
				
			||||||
 | 
					            f.setdelegate(filter.delegate)
 | 
				
			||||||
 | 
					            filter.setdelegate(None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    class Tracer(Delegator):
 | 
				
			||||||
 | 
					        def __init__(self, name):
 | 
				
			||||||
 | 
					            self.name = name
 | 
				
			||||||
 | 
					            Delegator.__init__(self, None)
 | 
				
			||||||
 | 
					        def insert(self, *args):
 | 
				
			||||||
 | 
					            print self.name, ": insert", args
 | 
				
			||||||
 | 
					            apply(self.delegate.insert, args)
 | 
				
			||||||
 | 
					        def delete(self, *args):
 | 
				
			||||||
 | 
					            print self.name, ": delete", args
 | 
				
			||||||
 | 
					            apply(self.delegate.delete, args)
 | 
				
			||||||
 | 
					    from Tkinter import *
 | 
				
			||||||
 | 
					    root = Tk()
 | 
				
			||||||
 | 
					    root.wm_protocol("WM_DELETE_WINDOW", root.quit)
 | 
				
			||||||
 | 
					    text = Text()
 | 
				
			||||||
 | 
					    text.pack()
 | 
				
			||||||
 | 
					    text.focus_set()
 | 
				
			||||||
 | 
					    p = Percolator(text)
 | 
				
			||||||
 | 
					    t1 = Tracer("t1")
 | 
				
			||||||
 | 
					    t2 = Tracer("t2")
 | 
				
			||||||
 | 
					    p.insertfilter(t1)
 | 
				
			||||||
 | 
					    p.insertfilter(t2)
 | 
				
			||||||
 | 
					    root.mainloop()
 | 
				
			||||||
 | 
					    p.removefilter(t2)
 | 
				
			||||||
 | 
					    root.mainloop()
 | 
				
			||||||
 | 
					    p.insertfilter(t2)
 | 
				
			||||||
 | 
					    p.removefilter(t1)
 | 
				
			||||||
 | 
					    root.mainloop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										569
									
								
								Lib/idlelib/PyParse.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										569
									
								
								Lib/idlelib/PyParse.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,569 @@
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Reason last stmt is continued (or C_NONE if it's not).
 | 
				
			||||||
 | 
					C_NONE, C_BACKSLASH, C_STRING, C_BRACKET = range(4)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if 0:   # for throwaway debugging output
 | 
				
			||||||
 | 
					    def dump(*stuff):
 | 
				
			||||||
 | 
					        sys.__stdout__.write(string.join(map(str, stuff), " ") + "\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Find what looks like the start of a popular stmt.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_synchre = re.compile(r"""
 | 
				
			||||||
 | 
					    ^
 | 
				
			||||||
 | 
					    [ \t]*
 | 
				
			||||||
 | 
					    (?: if
 | 
				
			||||||
 | 
					    |   for
 | 
				
			||||||
 | 
					    |   while
 | 
				
			||||||
 | 
					    |   else
 | 
				
			||||||
 | 
					    |   def
 | 
				
			||||||
 | 
					    |   return
 | 
				
			||||||
 | 
					    |   assert
 | 
				
			||||||
 | 
					    |   break
 | 
				
			||||||
 | 
					    |   class
 | 
				
			||||||
 | 
					    |   continue
 | 
				
			||||||
 | 
					    |   elif
 | 
				
			||||||
 | 
					    |   try
 | 
				
			||||||
 | 
					    |   except
 | 
				
			||||||
 | 
					    |   raise
 | 
				
			||||||
 | 
					    |   import
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    \b
 | 
				
			||||||
 | 
					""", re.VERBOSE | re.MULTILINE).search
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Match blank line or non-indenting comment line.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_junkre = re.compile(r"""
 | 
				
			||||||
 | 
					    [ \t]*
 | 
				
			||||||
 | 
					    (?: \# \S .* )?
 | 
				
			||||||
 | 
					    \n
 | 
				
			||||||
 | 
					""", re.VERBOSE).match
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Match any flavor of string; the terminating quote is optional
 | 
				
			||||||
 | 
					# so that we're robust in the face of incomplete program text.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_match_stringre = re.compile(r"""
 | 
				
			||||||
 | 
					    \""" [^"\\]* (?:
 | 
				
			||||||
 | 
					                     (?: \\. | "(?!"") )
 | 
				
			||||||
 | 
					                     [^"\\]*
 | 
				
			||||||
 | 
					                 )*
 | 
				
			||||||
 | 
					    (?: \""" )?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					|   " [^"\\\n]* (?: \\. [^"\\\n]* )* "?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					|   ''' [^'\\]* (?:
 | 
				
			||||||
 | 
					                   (?: \\. | '(?!'') )
 | 
				
			||||||
 | 
					                   [^'\\]*
 | 
				
			||||||
 | 
					                )*
 | 
				
			||||||
 | 
					    (?: ''' )?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					|   ' [^'\\\n]* (?: \\. [^'\\\n]* )* '?
 | 
				
			||||||
 | 
					""", re.VERBOSE | re.DOTALL).match
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Match a line that starts with something interesting;
 | 
				
			||||||
 | 
					# used to find the first item of a bracket structure.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_itemre = re.compile(r"""
 | 
				
			||||||
 | 
					    [ \t]*
 | 
				
			||||||
 | 
					    [^\s#\\]    # if we match, m.end()-1 is the interesting char
 | 
				
			||||||
 | 
					""", re.VERBOSE).match
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Match start of stmts that should be followed by a dedent.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_closere = re.compile(r"""
 | 
				
			||||||
 | 
					    \s*
 | 
				
			||||||
 | 
					    (?: return
 | 
				
			||||||
 | 
					    |   break
 | 
				
			||||||
 | 
					    |   continue
 | 
				
			||||||
 | 
					    |   raise
 | 
				
			||||||
 | 
					    |   pass
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					    \b
 | 
				
			||||||
 | 
					""", re.VERBOSE).match
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Chew up non-special chars as quickly as possible.  If match is
 | 
				
			||||||
 | 
					# successful, m.end() less 1 is the index of the last boring char
 | 
				
			||||||
 | 
					# matched.  If match is unsuccessful, the string starts with an
 | 
				
			||||||
 | 
					# interesting char.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_chew_ordinaryre = re.compile(r"""
 | 
				
			||||||
 | 
					    [^[\](){}#'"\\]+
 | 
				
			||||||
 | 
					""", re.VERBOSE).match
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Build translation table to map uninteresting chars to "x", open
 | 
				
			||||||
 | 
					# brackets to "(", and close brackets to ")".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_tran = ['x'] * 256
 | 
				
			||||||
 | 
					for ch in "({[":
 | 
				
			||||||
 | 
					    _tran[ord(ch)] = '('
 | 
				
			||||||
 | 
					for ch in ")}]":
 | 
				
			||||||
 | 
					    _tran[ord(ch)] = ')'
 | 
				
			||||||
 | 
					for ch in "\"'\\\n#":
 | 
				
			||||||
 | 
					    _tran[ord(ch)] = ch
 | 
				
			||||||
 | 
					_tran = string.join(_tran, '')
 | 
				
			||||||
 | 
					del ch
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Parser:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, indentwidth, tabwidth):
 | 
				
			||||||
 | 
					        self.indentwidth = indentwidth
 | 
				
			||||||
 | 
					        self.tabwidth = tabwidth
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_str(self, str):
 | 
				
			||||||
 | 
					        assert len(str) == 0 or str[-1] == '\n'
 | 
				
			||||||
 | 
					        self.str = str
 | 
				
			||||||
 | 
					        self.study_level = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # 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:
 | 
				
			||||||
 | 
					    # 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.
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    # Ack, hack: in the shell window this kills us, because there's
 | 
				
			||||||
 | 
					    # no way to tell the differences between output, >>> etc and
 | 
				
			||||||
 | 
					    # user input.  Indeed, IDLE's first output line makes the rest
 | 
				
			||||||
 | 
					    # 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,
 | 
				
			||||||
 | 
					                              _rfind=string.rfind,
 | 
				
			||||||
 | 
					                              _synchre=_synchre):
 | 
				
			||||||
 | 
					        str, pos = self.str, None
 | 
				
			||||||
 | 
					        if use_ps1:
 | 
				
			||||||
 | 
					            # shell window
 | 
				
			||||||
 | 
					            ps1 = '\n' + sys.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:]
 | 
				
			||||||
 | 
					            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
 | 
				
			||||||
 | 
					    # find_good_parse_start's result.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_lo(self, lo):
 | 
				
			||||||
 | 
					        assert lo == 0 or self.str[lo-1] == '\n'
 | 
				
			||||||
 | 
					        if lo > 0:
 | 
				
			||||||
 | 
					            self.str = self.str[lo:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # As quickly as humanly possible <wink>, find the line numbers (0-
 | 
				
			||||||
 | 
					    # based) of the non-continuation lines.
 | 
				
			||||||
 | 
					    # Creates self.{goodlines, continuation}.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _study1(self, _replace=string.replace, _find=string.find):
 | 
				
			||||||
 | 
					        if self.study_level >= 1:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.study_level = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Map all uninteresting characters to "x", all open brackets
 | 
				
			||||||
 | 
					        # to "(", all close brackets to ")", then collapse runs of
 | 
				
			||||||
 | 
					        # uninteresting characters.  This can cut the number of chars
 | 
				
			||||||
 | 
					        # by a factor of 10-40, and so greatly speed the following loop.
 | 
				
			||||||
 | 
					        str = self.str
 | 
				
			||||||
 | 
					        str = string.translate(str, _tran)
 | 
				
			||||||
 | 
					        str = _replace(str, 'xxxxxxxx', 'x')
 | 
				
			||||||
 | 
					        str = _replace(str, 'xxxx', 'x')
 | 
				
			||||||
 | 
					        str = _replace(str, 'xx', 'x')
 | 
				
			||||||
 | 
					        str = _replace(str, 'xx', 'x')
 | 
				
			||||||
 | 
					        str = _replace(str, '\nx', '\n')
 | 
				
			||||||
 | 
					        # note that replacing x\n with \n would be incorrect, because
 | 
				
			||||||
 | 
					        # x may be preceded by a backslash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # March over the squashed version of the program, accumulating
 | 
				
			||||||
 | 
					        # the line numbers of non-continued stmts, and determining
 | 
				
			||||||
 | 
					        # whether & why the last stmt is a continuation.
 | 
				
			||||||
 | 
					        continuation = C_NONE
 | 
				
			||||||
 | 
					        level = lno = 0     # level is nesting level; lno is line number
 | 
				
			||||||
 | 
					        self.goodlines = goodlines = [0]
 | 
				
			||||||
 | 
					        push_good = goodlines.append
 | 
				
			||||||
 | 
					        i, n = 0, len(str)
 | 
				
			||||||
 | 
					        while i < n:
 | 
				
			||||||
 | 
					            ch = str[i]
 | 
				
			||||||
 | 
					            i = i+1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # cases are checked in decreasing order of frequency
 | 
				
			||||||
 | 
					            if ch == 'x':
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ch == '\n':
 | 
				
			||||||
 | 
					                lno = lno + 1
 | 
				
			||||||
 | 
					                if level == 0:
 | 
				
			||||||
 | 
					                    push_good(lno)
 | 
				
			||||||
 | 
					                    # else we're in an unclosed bracket structure
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ch == '(':
 | 
				
			||||||
 | 
					                level = level + 1
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ch == ')':
 | 
				
			||||||
 | 
					                if level:
 | 
				
			||||||
 | 
					                    level = level - 1
 | 
				
			||||||
 | 
					                    # else the program is invalid, but we can't complain
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ch == '"' or ch == "'":
 | 
				
			||||||
 | 
					                # consume the string
 | 
				
			||||||
 | 
					                quote = ch
 | 
				
			||||||
 | 
					                if str[i-1:i+2] == quote * 3:
 | 
				
			||||||
 | 
					                    quote = quote * 3
 | 
				
			||||||
 | 
					                w = len(quote) - 1
 | 
				
			||||||
 | 
					                i = i+w
 | 
				
			||||||
 | 
					                while i < n:
 | 
				
			||||||
 | 
					                    ch = str[i]
 | 
				
			||||||
 | 
					                    i = i+1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if ch == 'x':
 | 
				
			||||||
 | 
					                        continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if str[i-1:i+w] == quote:
 | 
				
			||||||
 | 
					                        i = i+w
 | 
				
			||||||
 | 
					                        break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if ch == '\n':
 | 
				
			||||||
 | 
					                        lno = lno + 1
 | 
				
			||||||
 | 
					                        if w == 0:
 | 
				
			||||||
 | 
					                            # unterminated single-quoted string
 | 
				
			||||||
 | 
					                            if level == 0:
 | 
				
			||||||
 | 
					                                push_good(lno)
 | 
				
			||||||
 | 
					                            break
 | 
				
			||||||
 | 
					                        continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    if ch == '\\':
 | 
				
			||||||
 | 
					                        assert i < n
 | 
				
			||||||
 | 
					                        if str[i] == '\n':
 | 
				
			||||||
 | 
					                            lno = lno + 1
 | 
				
			||||||
 | 
					                        i = i+1
 | 
				
			||||||
 | 
					                        continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                    # else comment char or paren inside string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    # didn't break out of the loop, so we're still
 | 
				
			||||||
 | 
					                    # inside a string
 | 
				
			||||||
 | 
					                    continuation = C_STRING
 | 
				
			||||||
 | 
					                continue    # with outer loop
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ch == '#':
 | 
				
			||||||
 | 
					                # consume the comment
 | 
				
			||||||
 | 
					                i = _find(str, '\n', i)
 | 
				
			||||||
 | 
					                assert i >= 0
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            assert ch == '\\'
 | 
				
			||||||
 | 
					            assert i < n
 | 
				
			||||||
 | 
					            if str[i] == '\n':
 | 
				
			||||||
 | 
					                lno = lno + 1
 | 
				
			||||||
 | 
					                if i+1 == n:
 | 
				
			||||||
 | 
					                    continuation = C_BACKSLASH
 | 
				
			||||||
 | 
					            i = i+1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # The last stmt may be continued for all 3 reasons.
 | 
				
			||||||
 | 
					        # String continuation takes precedence over bracket
 | 
				
			||||||
 | 
					        # continuation, which beats backslash continuation.
 | 
				
			||||||
 | 
					        if continuation != C_STRING and level > 0:
 | 
				
			||||||
 | 
					            continuation = C_BRACKET
 | 
				
			||||||
 | 
					        self.continuation = continuation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Push the final line number as a sentinel value, regardless of
 | 
				
			||||||
 | 
					        # whether it's continued.
 | 
				
			||||||
 | 
					        assert (continuation == C_NONE) == (goodlines[-1] == lno)
 | 
				
			||||||
 | 
					        if goodlines[-1] != lno:
 | 
				
			||||||
 | 
					            push_good(lno)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_continuation_type(self):
 | 
				
			||||||
 | 
					        self._study1()
 | 
				
			||||||
 | 
					        return self.continuation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # study1 was sufficient to determine the continuation status,
 | 
				
			||||||
 | 
					    # but doing more requires looking at every character.  study2
 | 
				
			||||||
 | 
					    # does this for the last interesting statement in the block.
 | 
				
			||||||
 | 
					    # Creates:
 | 
				
			||||||
 | 
					    #     self.stmt_start, stmt_end
 | 
				
			||||||
 | 
					    #         slice indices of last interesting stmt
 | 
				
			||||||
 | 
					    #     self.lastch
 | 
				
			||||||
 | 
					    #         last non-whitespace character before optional trailing
 | 
				
			||||||
 | 
					    #         comment
 | 
				
			||||||
 | 
					    #     self.lastopenbracketpos
 | 
				
			||||||
 | 
					    #         if continuation is C_BRACKET, index of last open bracket
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _study2(self, _rfind=string.rfind, _find=string.find,
 | 
				
			||||||
 | 
					                      _ws=string.whitespace):
 | 
				
			||||||
 | 
					        if self.study_level >= 2:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self._study1()
 | 
				
			||||||
 | 
					        self.study_level = 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Set p and q to slice indices of last interesting stmt.
 | 
				
			||||||
 | 
					        str, goodlines = self.str, self.goodlines
 | 
				
			||||||
 | 
					        i = len(goodlines) - 1
 | 
				
			||||||
 | 
					        p = len(str)    # index of newest line
 | 
				
			||||||
 | 
					        while i:
 | 
				
			||||||
 | 
					            assert p
 | 
				
			||||||
 | 
					            # p is the index of the stmt at line number goodlines[i].
 | 
				
			||||||
 | 
					            # Move p back to the stmt at line number goodlines[i-1].
 | 
				
			||||||
 | 
					            q = p
 | 
				
			||||||
 | 
					            for nothing in range(goodlines[i-1], goodlines[i]):
 | 
				
			||||||
 | 
					                # tricky: sets p to 0 if no preceding newline
 | 
				
			||||||
 | 
					                p = _rfind(str, '\n', 0, p-1) + 1
 | 
				
			||||||
 | 
					            # The stmt str[p:q] isn't a continuation, but may be blank
 | 
				
			||||||
 | 
					            # or a non-indenting comment line.
 | 
				
			||||||
 | 
					            if  _junkre(str, p):
 | 
				
			||||||
 | 
					                i = i-1
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					        if i == 0:
 | 
				
			||||||
 | 
					            # nothing but junk!
 | 
				
			||||||
 | 
					            assert p == 0
 | 
				
			||||||
 | 
					            q = p
 | 
				
			||||||
 | 
					        self.stmt_start, self.stmt_end = p, q
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # Analyze this stmt, to find the last open bracket (if any)
 | 
				
			||||||
 | 
					        # and last interesting character (if any).
 | 
				
			||||||
 | 
					        lastch = ""
 | 
				
			||||||
 | 
					        stack = []  # stack of open bracket indices
 | 
				
			||||||
 | 
					        push_stack = stack.append
 | 
				
			||||||
 | 
					        while p < q:
 | 
				
			||||||
 | 
					            # suck up all except ()[]{}'"#\\
 | 
				
			||||||
 | 
					            m = _chew_ordinaryre(str, p, q)
 | 
				
			||||||
 | 
					            if m:
 | 
				
			||||||
 | 
					                # we skipped at least one boring char
 | 
				
			||||||
 | 
					                p = m.end()
 | 
				
			||||||
 | 
					                # back up over totally boring whitespace
 | 
				
			||||||
 | 
					                i = p-1    # index of last boring char
 | 
				
			||||||
 | 
					                while i >= 0 and str[i] in " \t\n":
 | 
				
			||||||
 | 
					                    i = i-1
 | 
				
			||||||
 | 
					                if i >= 0:
 | 
				
			||||||
 | 
					                    lastch = str[i]
 | 
				
			||||||
 | 
					                if p >= q:
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            ch = str[p]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ch in "([{":
 | 
				
			||||||
 | 
					                push_stack(p)
 | 
				
			||||||
 | 
					                lastch = ch
 | 
				
			||||||
 | 
					                p = p+1
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ch in ")]}":
 | 
				
			||||||
 | 
					                if stack:
 | 
				
			||||||
 | 
					                    del stack[-1]
 | 
				
			||||||
 | 
					                lastch = ch
 | 
				
			||||||
 | 
					                p = p+1
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ch == '"' or ch == "'":
 | 
				
			||||||
 | 
					                # consume string
 | 
				
			||||||
 | 
					                # Note that study1 did this with a Python loop, but
 | 
				
			||||||
 | 
					                # we use a regexp here; the reason is speed in both
 | 
				
			||||||
 | 
					                # cases; the string may be huge, but study1 pre-squashed
 | 
				
			||||||
 | 
					                # strings to a couple of characters per line.  study1
 | 
				
			||||||
 | 
					                # also needed to keep track of newlines, and we don't
 | 
				
			||||||
 | 
					                # have to.
 | 
				
			||||||
 | 
					                lastch = ch
 | 
				
			||||||
 | 
					                p = _match_stringre(str, p, q).end()
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if ch == '#':
 | 
				
			||||||
 | 
					                # consume comment and trailing newline
 | 
				
			||||||
 | 
					                p = _find(str, '\n', p, q) + 1
 | 
				
			||||||
 | 
					                assert p > 0
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            assert ch == '\\'
 | 
				
			||||||
 | 
					            p = p+1     # beyond backslash
 | 
				
			||||||
 | 
					            assert p < q
 | 
				
			||||||
 | 
					            if str[p] != '\n':
 | 
				
			||||||
 | 
					                # the program is invalid, but can't complain
 | 
				
			||||||
 | 
					                lastch = ch + str[p]
 | 
				
			||||||
 | 
					            p = p+1     # beyond escaped char
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # end while p < q:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.lastch = lastch
 | 
				
			||||||
 | 
					        if stack:
 | 
				
			||||||
 | 
					            self.lastopenbracketpos = stack[-1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Assuming continuation is C_BRACKET, return the number
 | 
				
			||||||
 | 
					    # of spaces the next line should be indented.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def compute_bracket_indent(self, _find=string.find):
 | 
				
			||||||
 | 
					        self._study2()
 | 
				
			||||||
 | 
					        assert self.continuation == C_BRACKET
 | 
				
			||||||
 | 
					        j = self.lastopenbracketpos
 | 
				
			||||||
 | 
					        str = self.str
 | 
				
			||||||
 | 
					        n = len(str)
 | 
				
			||||||
 | 
					        origi = i = string.rfind(str, '\n', 0, j) + 1
 | 
				
			||||||
 | 
					        j = j+1     # one beyond open bracket
 | 
				
			||||||
 | 
					        # find first list item; set i to start of its line
 | 
				
			||||||
 | 
					        while j < n:
 | 
				
			||||||
 | 
					            m = _itemre(str, j)
 | 
				
			||||||
 | 
					            if m:
 | 
				
			||||||
 | 
					                j = m.end() - 1     # index of first interesting char
 | 
				
			||||||
 | 
					                extra = 0
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                # this line is junk; advance to next line
 | 
				
			||||||
 | 
					                i = j = _find(str, '\n', j) + 1
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            # nothing interesting follows the bracket;
 | 
				
			||||||
 | 
					            # reproduce the bracket line's indentation + a level
 | 
				
			||||||
 | 
					            j = i = origi
 | 
				
			||||||
 | 
					            while str[j] in " \t":
 | 
				
			||||||
 | 
					                j = j+1
 | 
				
			||||||
 | 
					            extra = self.indentwidth
 | 
				
			||||||
 | 
					        return len(string.expandtabs(str[i:j],
 | 
				
			||||||
 | 
					                                     self.tabwidth)) + extra
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Return number of physical lines in last stmt (whether or not
 | 
				
			||||||
 | 
					    # it's an interesting stmt!  this is intended to be called when
 | 
				
			||||||
 | 
					    # continuation is C_BACKSLASH).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_num_lines_in_stmt(self):
 | 
				
			||||||
 | 
					        self._study1()
 | 
				
			||||||
 | 
					        goodlines = self.goodlines
 | 
				
			||||||
 | 
					        return goodlines[-1] - goodlines[-2]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Assuming continuation is C_BACKSLASH, return the number of spaces
 | 
				
			||||||
 | 
					    # the next line should be indented.  Also assuming the new line is
 | 
				
			||||||
 | 
					    # the first one following the initial line of the stmt.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def compute_backslash_indent(self):
 | 
				
			||||||
 | 
					        self._study2()
 | 
				
			||||||
 | 
					        assert self.continuation == C_BACKSLASH
 | 
				
			||||||
 | 
					        str = self.str
 | 
				
			||||||
 | 
					        i = self.stmt_start
 | 
				
			||||||
 | 
					        while str[i] in " \t":
 | 
				
			||||||
 | 
					            i = i+1
 | 
				
			||||||
 | 
					        startpos = i
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # See whether the initial line starts an assignment stmt; i.e.,
 | 
				
			||||||
 | 
					        # look for an = operator
 | 
				
			||||||
 | 
					        endpos = string.find(str, '\n', startpos) + 1
 | 
				
			||||||
 | 
					        found = level = 0
 | 
				
			||||||
 | 
					        while i < endpos:
 | 
				
			||||||
 | 
					            ch = str[i]
 | 
				
			||||||
 | 
					            if ch in "([{":
 | 
				
			||||||
 | 
					                level = level + 1
 | 
				
			||||||
 | 
					                i = i+1
 | 
				
			||||||
 | 
					            elif ch in ")]}":
 | 
				
			||||||
 | 
					                if level:
 | 
				
			||||||
 | 
					                    level = level - 1
 | 
				
			||||||
 | 
					                i = i+1
 | 
				
			||||||
 | 
					            elif ch == '"' or ch == "'":
 | 
				
			||||||
 | 
					                i = _match_stringre(str, i, endpos).end()
 | 
				
			||||||
 | 
					            elif ch == '#':
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            elif level == 0 and ch == '=' and \
 | 
				
			||||||
 | 
					                   (i == 0 or str[i-1] not in "=<>!") and \
 | 
				
			||||||
 | 
					                   str[i+1] != '=':
 | 
				
			||||||
 | 
					                found = 1
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                i = i+1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if found:
 | 
				
			||||||
 | 
					            # found a legit =, but it may be the last interesting
 | 
				
			||||||
 | 
					            # thing on the line
 | 
				
			||||||
 | 
					            i = i+1     # move beyond the =
 | 
				
			||||||
 | 
					            found = re.match(r"\s*\\", str[i:endpos]) is None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not found:
 | 
				
			||||||
 | 
					            # oh well ... settle for moving beyond the first chunk
 | 
				
			||||||
 | 
					            # of non-whitespace chars
 | 
				
			||||||
 | 
					            i = startpos
 | 
				
			||||||
 | 
					            while str[i] not in " \t\n":
 | 
				
			||||||
 | 
					                i = i+1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return len(string.expandtabs(str[self.stmt_start :
 | 
				
			||||||
 | 
					                                         i],
 | 
				
			||||||
 | 
					                                     self.tabwidth)) + 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Return the leading whitespace on the initial line of the last
 | 
				
			||||||
 | 
					    # interesting stmt.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_base_indent_string(self):
 | 
				
			||||||
 | 
					        self._study2()
 | 
				
			||||||
 | 
					        i, n = self.stmt_start, self.stmt_end
 | 
				
			||||||
 | 
					        j = i
 | 
				
			||||||
 | 
					        str = self.str
 | 
				
			||||||
 | 
					        while j < n and str[j] in " \t":
 | 
				
			||||||
 | 
					            j = j + 1
 | 
				
			||||||
 | 
					        return str[i:j]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Did the last interesting stmt open a block?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def is_block_opener(self):
 | 
				
			||||||
 | 
					        self._study2()
 | 
				
			||||||
 | 
					        return self.lastch == ':'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Did the last interesting stmt close a block?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def is_block_closer(self):
 | 
				
			||||||
 | 
					        self._study2()
 | 
				
			||||||
 | 
					        return _closere(self.str, self.stmt_start) is not None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # index of last open bracket ({[, or None if none
 | 
				
			||||||
 | 
					    lastopenbracketpos = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_last_open_bracket_pos(self):
 | 
				
			||||||
 | 
					        self._study2()
 | 
				
			||||||
 | 
					        return self.lastopenbracketpos
 | 
				
			||||||
							
								
								
									
										860
									
								
								Lib/idlelib/PyShell.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										860
									
								
								Lib/idlelib/PyShell.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,860 @@
 | 
				
			||||||
 | 
					#! /usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# changes by dscherer@cmu.edu
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#   the main() function has been replaced by a whole class, in order to
 | 
				
			||||||
 | 
					#     address the constraint that only one process can sit on the port
 | 
				
			||||||
 | 
					#     hard-coded into the loader.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#     It attempts to load the RPC protocol server and publish itself.  If
 | 
				
			||||||
 | 
					#     that fails, it assumes that some other copy of IDLE is already running
 | 
				
			||||||
 | 
					#     on the port and attempts to contact it.  It then uses the RPC mechanism
 | 
				
			||||||
 | 
					#     to ask that copy to do whatever it was instructed (via the command
 | 
				
			||||||
 | 
					#     line) to do.  (Think netscape -remote).  The handling of command line
 | 
				
			||||||
 | 
					#     arguments for remotes is still very incomplete.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#   default behavior (no command line options) is to NOT start the Python
 | 
				
			||||||
 | 
					#     Shell.  If files are specified, they are opened, otherwise a single
 | 
				
			||||||
 | 
					#     blank editor window opens.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#   If any command line -options are specified, a shell does appear.  This
 | 
				
			||||||
 | 
					#     is necessary to make the current semantics of the options make sense.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import spawn
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import getopt
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import protocol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import linecache
 | 
				
			||||||
 | 
					from code import InteractiveInterpreter
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					import tkMessageBox
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from EditorWindow import EditorWindow, fixwordbreaks
 | 
				
			||||||
 | 
					from FileList import FileList
 | 
				
			||||||
 | 
					from ColorDelegator import ColorDelegator
 | 
				
			||||||
 | 
					from UndoDelegator import UndoDelegator
 | 
				
			||||||
 | 
					from OutputWindow import OutputWindow, OnDemandOutputWindow
 | 
				
			||||||
 | 
					from IdleConf import idleconf
 | 
				
			||||||
 | 
					import idlever
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# We need to patch linecache.checkcache, because we don't want it
 | 
				
			||||||
 | 
					# to throw away our <pyshell#...> entries.
 | 
				
			||||||
 | 
					# Rather than repeating its code here, we save those entries,
 | 
				
			||||||
 | 
					# then call the original function, and then restore the saved entries.
 | 
				
			||||||
 | 
					def linecache_checkcache(orig_checkcache=linecache.checkcache):
 | 
				
			||||||
 | 
					    cache = linecache.cache
 | 
				
			||||||
 | 
					    save = {}
 | 
				
			||||||
 | 
					    for filename in cache.keys():
 | 
				
			||||||
 | 
					        if filename[:1] + filename[-1:] == '<>':
 | 
				
			||||||
 | 
					            save[filename] = cache[filename]
 | 
				
			||||||
 | 
					    orig_checkcache()
 | 
				
			||||||
 | 
					    cache.update(save)
 | 
				
			||||||
 | 
					linecache.checkcache = linecache_checkcache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Note: <<newline-and-indent>> event is defined in AutoIndent.py
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<plain-newline-and-indent>>
 | 
				
			||||||
 | 
					#$ win <Control-j>
 | 
				
			||||||
 | 
					#$ unix <Control-j>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<beginning-of-line>>
 | 
				
			||||||
 | 
					#$ win <Control-a>
 | 
				
			||||||
 | 
					#$ win <Home>
 | 
				
			||||||
 | 
					#$ unix <Control-a>
 | 
				
			||||||
 | 
					#$ unix <Home>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<history-next>>
 | 
				
			||||||
 | 
					#$ win <Alt-n>
 | 
				
			||||||
 | 
					#$ unix <Alt-n>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<history-previous>>
 | 
				
			||||||
 | 
					#$ win <Alt-p>
 | 
				
			||||||
 | 
					#$ unix <Alt-p>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<interrupt-execution>>
 | 
				
			||||||
 | 
					#$ win <Control-c>
 | 
				
			||||||
 | 
					#$ unix <Control-c>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<end-of-file>>
 | 
				
			||||||
 | 
					#$ win <Control-d>
 | 
				
			||||||
 | 
					#$ unix <Control-d>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<open-stack-viewer>>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<toggle-debugger>>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PyShellEditorWindow(EditorWindow):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Regular text edit window when a shell is present
 | 
				
			||||||
 | 
					    # XXX ought to merge with regular editor window
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, *args):
 | 
				
			||||||
 | 
					        apply(EditorWindow.__init__, (self,) + args)
 | 
				
			||||||
 | 
					        self.text.bind("<<set-breakpoint-here>>", self.set_breakpoint_here)
 | 
				
			||||||
 | 
					        self.text.bind("<<open-python-shell>>", self.flist.open_shell)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    rmenu_specs = [
 | 
				
			||||||
 | 
					        ("Set breakpoint here", "<<set-breakpoint-here>>"),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_breakpoint_here(self, event=None):
 | 
				
			||||||
 | 
					        if not self.flist.pyshell or not self.flist.pyshell.interp.debugger:
 | 
				
			||||||
 | 
					            self.text.bell()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.flist.pyshell.interp.debugger.set_breakpoint_here(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PyShellFileList(FileList):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # File list when a shell is present
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    EditorWindow = PyShellEditorWindow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pyshell = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def open_shell(self, event=None):
 | 
				
			||||||
 | 
					        if self.pyshell:
 | 
				
			||||||
 | 
					            self.pyshell.wakeup()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.pyshell = PyShell(self)
 | 
				
			||||||
 | 
					            self.pyshell.begin()
 | 
				
			||||||
 | 
					        return self.pyshell
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ModifiedColorDelegator(ColorDelegator):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Colorizer for the shell window itself
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def recolorize_main(self):
 | 
				
			||||||
 | 
					        self.tag_remove("TODO", "1.0", "iomark")
 | 
				
			||||||
 | 
					        self.tag_add("SYNC", "1.0", "iomark")
 | 
				
			||||||
 | 
					        ColorDelegator.recolorize_main(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tagdefs = ColorDelegator.tagdefs.copy()
 | 
				
			||||||
 | 
					    cconf = idleconf.getsection('Colors')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tagdefs.update({
 | 
				
			||||||
 | 
					        "stdin": cconf.getcolor("stdin"),
 | 
				
			||||||
 | 
					        "stdout": cconf.getcolor("stdout"),
 | 
				
			||||||
 | 
					        "stderr": cconf.getcolor("stderr"),
 | 
				
			||||||
 | 
					        "console": cconf.getcolor("console"),
 | 
				
			||||||
 | 
					        "ERROR": cconf.getcolor("ERROR"),
 | 
				
			||||||
 | 
						None: cconf.getcolor("normal"),
 | 
				
			||||||
 | 
					    })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ModifiedUndoDelegator(UndoDelegator):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Forbid insert/delete before the I/O mark
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def insert(self, index, chars, tags=None):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            if self.delegate.compare(index, "<", "iomark"):
 | 
				
			||||||
 | 
					                self.delegate.bell()
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					        except TclError:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        UndoDelegator.insert(self, index, chars, tags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete(self, index1, index2=None):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            if self.delegate.compare(index1, "<", "iomark"):
 | 
				
			||||||
 | 
					                self.delegate.bell()
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					        except TclError:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        UndoDelegator.delete(self, index1, index2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ModifiedInterpreter(InteractiveInterpreter):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, tkconsole):
 | 
				
			||||||
 | 
					        self.tkconsole = tkconsole
 | 
				
			||||||
 | 
					        locals = sys.modules['__main__'].__dict__
 | 
				
			||||||
 | 
					        InteractiveInterpreter.__init__(self, locals=locals)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    gid = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def execsource(self, source):
 | 
				
			||||||
 | 
					        # Like runsource() but assumes complete exec source
 | 
				
			||||||
 | 
					        filename = self.stuffsource(source)
 | 
				
			||||||
 | 
					        self.execfile(filename, source)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def execfile(self, filename, source=None):
 | 
				
			||||||
 | 
					        # Execute an existing file
 | 
				
			||||||
 | 
					        if source is None:
 | 
				
			||||||
 | 
					            source = open(filename, "r").read()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            code = compile(source, filename, "exec")
 | 
				
			||||||
 | 
					        except (OverflowError, SyntaxError):
 | 
				
			||||||
 | 
					            self.tkconsole.resetoutput()
 | 
				
			||||||
 | 
					            InteractiveInterpreter.showsyntaxerror(self, filename)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.runcode(code)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def runsource(self, source):
 | 
				
			||||||
 | 
					        # Extend base class to stuff the source in the line cache first
 | 
				
			||||||
 | 
					        filename = self.stuffsource(source)
 | 
				
			||||||
 | 
					        self.more = 0
 | 
				
			||||||
 | 
					        return InteractiveInterpreter.runsource(self, source, filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def stuffsource(self, source):
 | 
				
			||||||
 | 
					        # Stuff source in the filename cache
 | 
				
			||||||
 | 
					        filename = "<pyshell#%d>" % self.gid
 | 
				
			||||||
 | 
					        self.gid = self.gid + 1
 | 
				
			||||||
 | 
					        lines = string.split(source, "\n")
 | 
				
			||||||
 | 
					        linecache.cache[filename] = len(source)+1, 0, lines, filename
 | 
				
			||||||
 | 
					        return filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def showsyntaxerror(self, filename=None):
 | 
				
			||||||
 | 
					        # Extend base class to color the offending position
 | 
				
			||||||
 | 
					        # (instead of printing it and pointing at it with a caret)
 | 
				
			||||||
 | 
					        text = self.tkconsole.text
 | 
				
			||||||
 | 
					        stuff = self.unpackerror()
 | 
				
			||||||
 | 
					        if not stuff:
 | 
				
			||||||
 | 
					            self.tkconsole.resetoutput()
 | 
				
			||||||
 | 
					            InteractiveInterpreter.showsyntaxerror(self, filename)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        msg, lineno, offset, line = stuff
 | 
				
			||||||
 | 
					        if lineno == 1:
 | 
				
			||||||
 | 
					            pos = "iomark + %d chars" % (offset-1)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            pos = "iomark linestart + %d lines + %d chars" % (lineno-1,
 | 
				
			||||||
 | 
					                                                              offset-1)
 | 
				
			||||||
 | 
					        text.tag_add("ERROR", pos)
 | 
				
			||||||
 | 
					        text.see(pos)
 | 
				
			||||||
 | 
					        char = text.get(pos)
 | 
				
			||||||
 | 
					        if char and char in string.letters + string.digits + "_":
 | 
				
			||||||
 | 
					            text.tag_add("ERROR", pos + " wordstart", pos)
 | 
				
			||||||
 | 
					        self.tkconsole.resetoutput()
 | 
				
			||||||
 | 
					        self.write("SyntaxError: %s\n" % str(msg))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def unpackerror(self):
 | 
				
			||||||
 | 
					        type, value, tb = sys.exc_info()
 | 
				
			||||||
 | 
					        ok = type is SyntaxError
 | 
				
			||||||
 | 
					        if ok:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                msg, (dummy_filename, lineno, offset, line) = value
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                ok = 0
 | 
				
			||||||
 | 
					        if ok:
 | 
				
			||||||
 | 
					            return msg, lineno, offset, line
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def showtraceback(self):
 | 
				
			||||||
 | 
					        # Extend base class method to reset output properly
 | 
				
			||||||
 | 
					        text = self.tkconsole.text
 | 
				
			||||||
 | 
					        self.tkconsole.resetoutput()
 | 
				
			||||||
 | 
					        self.checklinecache()
 | 
				
			||||||
 | 
					        InteractiveInterpreter.showtraceback(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def checklinecache(self):
 | 
				
			||||||
 | 
					        c = linecache.cache
 | 
				
			||||||
 | 
					        for key in c.keys():
 | 
				
			||||||
 | 
					            if key[:1] + key[-1:] != "<>":
 | 
				
			||||||
 | 
					                del c[key]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    debugger = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setdebugger(self, debugger):
 | 
				
			||||||
 | 
					        self.debugger = debugger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getdebugger(self):
 | 
				
			||||||
 | 
					        return self.debugger
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def runcode(self, code):
 | 
				
			||||||
 | 
					        # Override base class method
 | 
				
			||||||
 | 
					        debugger = self.debugger
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.tkconsole.beginexecuting()
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                if debugger:
 | 
				
			||||||
 | 
					                    debugger.run(code, self.locals)
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    exec code in self.locals
 | 
				
			||||||
 | 
					            except SystemExit:
 | 
				
			||||||
 | 
					                if tkMessageBox.askyesno(
 | 
				
			||||||
 | 
					                    "Exit?",
 | 
				
			||||||
 | 
					                    "Do you want to exit altogether?",
 | 
				
			||||||
 | 
					                    default="yes",
 | 
				
			||||||
 | 
					                    master=self.tkconsole.text):
 | 
				
			||||||
 | 
					                    raise
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    self.showtraceback()
 | 
				
			||||||
 | 
					                    if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
 | 
				
			||||||
 | 
					                        self.tkconsole.open_stack_viewer()
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                self.showtraceback()
 | 
				
			||||||
 | 
					                if self.tkconsole.getvar("<<toggle-jit-stack-viewer>>"):
 | 
				
			||||||
 | 
					                    self.tkconsole.open_stack_viewer()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            self.tkconsole.endexecuting()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def write(self, s):
 | 
				
			||||||
 | 
					        # Override base class write
 | 
				
			||||||
 | 
					        self.tkconsole.console.write(s)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PyShell(OutputWindow):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    shell_title = "Python Shell"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Override classes
 | 
				
			||||||
 | 
					    ColorDelegator = ModifiedColorDelegator
 | 
				
			||||||
 | 
					    UndoDelegator = ModifiedUndoDelegator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Override menu bar specs
 | 
				
			||||||
 | 
					    menu_specs = PyShellEditorWindow.menu_specs[:]
 | 
				
			||||||
 | 
					    menu_specs.insert(len(menu_specs)-2, ("debug", "_Debug"))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # New classes
 | 
				
			||||||
 | 
					    from IdleHistory import History
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, flist=None):
 | 
				
			||||||
 | 
					        self.interp = ModifiedInterpreter(self)
 | 
				
			||||||
 | 
					        if flist is None:
 | 
				
			||||||
 | 
					            root = Tk()
 | 
				
			||||||
 | 
					            fixwordbreaks(root)
 | 
				
			||||||
 | 
					            root.withdraw()
 | 
				
			||||||
 | 
					            flist = PyShellFileList(root)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        OutputWindow.__init__(self, flist, None, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        import __builtin__
 | 
				
			||||||
 | 
					        __builtin__.quit = __builtin__.exit = "To exit, type Ctrl-D."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.auto = self.extensions["AutoIndent"] # Required extension
 | 
				
			||||||
 | 
					        self.auto.config(usetabs=1, indentwidth=8, context_use_ps1=1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        text.configure(wrap="char")
 | 
				
			||||||
 | 
					        text.bind("<<newline-and-indent>>", self.enter_callback)
 | 
				
			||||||
 | 
					        text.bind("<<plain-newline-and-indent>>", self.linefeed_callback)
 | 
				
			||||||
 | 
					        text.bind("<<interrupt-execution>>", self.cancel_callback)
 | 
				
			||||||
 | 
					        text.bind("<<beginning-of-line>>", self.home_callback)
 | 
				
			||||||
 | 
					        text.bind("<<end-of-file>>", self.eof_callback)
 | 
				
			||||||
 | 
					        text.bind("<<open-stack-viewer>>", self.open_stack_viewer)
 | 
				
			||||||
 | 
					        text.bind("<<toggle-debugger>>", self.toggle_debugger)
 | 
				
			||||||
 | 
					        text.bind("<<open-python-shell>>", self.flist.open_shell)
 | 
				
			||||||
 | 
					        text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.save_stdout = sys.stdout
 | 
				
			||||||
 | 
					        self.save_stderr = sys.stderr
 | 
				
			||||||
 | 
					        self.save_stdin = sys.stdin
 | 
				
			||||||
 | 
					        sys.stdout = PseudoFile(self, "stdout")
 | 
				
			||||||
 | 
					        sys.stderr = PseudoFile(self, "stderr")
 | 
				
			||||||
 | 
					        sys.stdin = self
 | 
				
			||||||
 | 
					        self.console = PseudoFile(self, "console")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.history = self.History(self.text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    reading = 0
 | 
				
			||||||
 | 
					    executing = 0
 | 
				
			||||||
 | 
					    canceled = 0
 | 
				
			||||||
 | 
					    endoffile = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def toggle_debugger(self, event=None):
 | 
				
			||||||
 | 
					        if self.executing:
 | 
				
			||||||
 | 
					            tkMessageBox.showerror("Don't debug now",
 | 
				
			||||||
 | 
					                "You can only toggle the debugger when idle",
 | 
				
			||||||
 | 
					                master=self.text)
 | 
				
			||||||
 | 
					            self.set_debugger_indicator()
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            db = self.interp.getdebugger()
 | 
				
			||||||
 | 
					            if db:
 | 
				
			||||||
 | 
					                self.close_debugger()
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                self.open_debugger()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_debugger_indicator(self):
 | 
				
			||||||
 | 
					        db = self.interp.getdebugger()
 | 
				
			||||||
 | 
					        self.setvar("<<toggle-debugger>>", not not db)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def toggle_jit_stack_viewer( self, event=None):
 | 
				
			||||||
 | 
					        pass # All we need is the variable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close_debugger(self):
 | 
				
			||||||
 | 
					        db = self.interp.getdebugger()
 | 
				
			||||||
 | 
					        if db:
 | 
				
			||||||
 | 
					            self.interp.setdebugger(None)
 | 
				
			||||||
 | 
					            db.close()
 | 
				
			||||||
 | 
					            self.resetoutput()
 | 
				
			||||||
 | 
					            self.console.write("[DEBUG OFF]\n")
 | 
				
			||||||
 | 
					            sys.ps1 = ">>> "
 | 
				
			||||||
 | 
					            self.showprompt()
 | 
				
			||||||
 | 
					        self.set_debugger_indicator()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def open_debugger(self):
 | 
				
			||||||
 | 
					        import Debugger
 | 
				
			||||||
 | 
					        self.interp.setdebugger(Debugger.Debugger(self))
 | 
				
			||||||
 | 
					        sys.ps1 = "[DEBUG ON]\n>>> "
 | 
				
			||||||
 | 
					        self.showprompt()
 | 
				
			||||||
 | 
					        self.set_debugger_indicator()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def beginexecuting(self):
 | 
				
			||||||
 | 
					        # Helper for ModifiedInterpreter
 | 
				
			||||||
 | 
					        self.resetoutput()
 | 
				
			||||||
 | 
					        self.executing = 1
 | 
				
			||||||
 | 
					        ##self._cancel_check = self.cancel_check
 | 
				
			||||||
 | 
					        ##sys.settrace(self._cancel_check)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def endexecuting(self):
 | 
				
			||||||
 | 
					        # Helper for ModifiedInterpreter
 | 
				
			||||||
 | 
					        ##sys.settrace(None)
 | 
				
			||||||
 | 
					        ##self._cancel_check = None
 | 
				
			||||||
 | 
					        self.executing = 0
 | 
				
			||||||
 | 
					        self.canceled = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self):
 | 
				
			||||||
 | 
					        # Extend base class method
 | 
				
			||||||
 | 
					        if self.executing:
 | 
				
			||||||
 | 
					            # XXX Need to ask a question here
 | 
				
			||||||
 | 
					            if not tkMessageBox.askokcancel(
 | 
				
			||||||
 | 
					                "Kill?",
 | 
				
			||||||
 | 
					                "The program is still running; do you want to kill it?",
 | 
				
			||||||
 | 
					                default="ok",
 | 
				
			||||||
 | 
					                master=self.text):
 | 
				
			||||||
 | 
					                return "cancel"
 | 
				
			||||||
 | 
					            self.canceled = 1
 | 
				
			||||||
 | 
					            if self.reading:
 | 
				
			||||||
 | 
					                self.top.quit()
 | 
				
			||||||
 | 
					            return "cancel"
 | 
				
			||||||
 | 
					        return PyShellEditorWindow.close(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _close(self):
 | 
				
			||||||
 | 
					        self.close_debugger()
 | 
				
			||||||
 | 
					        # Restore std streams
 | 
				
			||||||
 | 
					        sys.stdout = self.save_stdout
 | 
				
			||||||
 | 
					        sys.stderr = self.save_stderr
 | 
				
			||||||
 | 
					        sys.stdin = self.save_stdin
 | 
				
			||||||
 | 
					        # Break cycles
 | 
				
			||||||
 | 
					        self.interp = None
 | 
				
			||||||
 | 
					        self.console = None
 | 
				
			||||||
 | 
					        self.auto = None
 | 
				
			||||||
 | 
					        self.flist.pyshell = None
 | 
				
			||||||
 | 
					        self.history = None
 | 
				
			||||||
 | 
					        OutputWindow._close(self) # Really EditorWindow._close
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def ispythonsource(self, filename):
 | 
				
			||||||
 | 
					        # Override this so EditorWindow never removes the colorizer
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def short_title(self):
 | 
				
			||||||
 | 
					        return self.shell_title
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def begin(self):
 | 
				
			||||||
 | 
					        self.resetoutput()
 | 
				
			||||||
 | 
					        self.write("Python %s on %s\n%s\nIDLE %s -- press F1 for help\n" %
 | 
				
			||||||
 | 
					                   (sys.version, sys.platform, sys.copyright,
 | 
				
			||||||
 | 
					                    idlever.IDLE_VERSION))
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            sys.ps1
 | 
				
			||||||
 | 
					        except AttributeError:
 | 
				
			||||||
 | 
					            sys.ps1 = ">>> "
 | 
				
			||||||
 | 
					        self.showprompt()
 | 
				
			||||||
 | 
					        import Tkinter
 | 
				
			||||||
 | 
					        Tkinter._default_root = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def interact(self):
 | 
				
			||||||
 | 
					        self.begin()
 | 
				
			||||||
 | 
					        self.top.mainloop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def readline(self):
 | 
				
			||||||
 | 
					        save = self.reading
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.reading = 1
 | 
				
			||||||
 | 
					            self.top.mainloop()
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            self.reading = save
 | 
				
			||||||
 | 
					        line = self.text.get("iomark", "end-1c")
 | 
				
			||||||
 | 
					        self.resetoutput()
 | 
				
			||||||
 | 
					        if self.canceled:
 | 
				
			||||||
 | 
					            self.canceled = 0
 | 
				
			||||||
 | 
					            raise KeyboardInterrupt
 | 
				
			||||||
 | 
					        if self.endoffile:
 | 
				
			||||||
 | 
					            self.endoffile = 0
 | 
				
			||||||
 | 
					            return ""
 | 
				
			||||||
 | 
					        return line
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def isatty(self):
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def cancel_callback(self, event):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            if self.text.compare("sel.first", "!=", "sel.last"):
 | 
				
			||||||
 | 
					                return # Active selection -- always use default binding
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        if not (self.executing or self.reading):
 | 
				
			||||||
 | 
					            self.resetoutput()
 | 
				
			||||||
 | 
					            self.write("KeyboardInterrupt\n")
 | 
				
			||||||
 | 
					            self.showprompt()
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					        self.endoffile = 0
 | 
				
			||||||
 | 
					        self.canceled = 1
 | 
				
			||||||
 | 
					        if self.reading:
 | 
				
			||||||
 | 
					            self.top.quit()
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def eof_callback(self, event):
 | 
				
			||||||
 | 
					        if self.executing and not self.reading:
 | 
				
			||||||
 | 
					            return # Let the default binding (delete next char) take over
 | 
				
			||||||
 | 
					        if not (self.text.compare("iomark", "==", "insert") and
 | 
				
			||||||
 | 
					                self.text.compare("insert", "==", "end-1c")):
 | 
				
			||||||
 | 
					            return # Let the default binding (delete next char) take over
 | 
				
			||||||
 | 
					        if not self.executing:
 | 
				
			||||||
 | 
					##             if not tkMessageBox.askokcancel(
 | 
				
			||||||
 | 
					##                 "Exit?",
 | 
				
			||||||
 | 
					##                 "Are you sure you want to exit?",
 | 
				
			||||||
 | 
					##                 default="ok", master=self.text):
 | 
				
			||||||
 | 
					##                 return "break"
 | 
				
			||||||
 | 
					            self.resetoutput()
 | 
				
			||||||
 | 
					            self.close()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.canceled = 0
 | 
				
			||||||
 | 
					            self.endoffile = 1
 | 
				
			||||||
 | 
					            self.top.quit()
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def home_callback(self, event):
 | 
				
			||||||
 | 
					        if event.state != 0 and event.keysym == "Home":
 | 
				
			||||||
 | 
					            return # <Modifier-Home>; fall back to class binding
 | 
				
			||||||
 | 
					        if self.text.compare("iomark", "<=", "insert") and \
 | 
				
			||||||
 | 
					           self.text.compare("insert linestart", "<=", "iomark"):
 | 
				
			||||||
 | 
					            self.text.mark_set("insert", "iomark")
 | 
				
			||||||
 | 
					            self.text.tag_remove("sel", "1.0", "end")
 | 
				
			||||||
 | 
					            self.text.see("insert")
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def linefeed_callback(self, event):
 | 
				
			||||||
 | 
					        # Insert a linefeed without entering anything (still autoindented)
 | 
				
			||||||
 | 
					        if self.reading:
 | 
				
			||||||
 | 
					            self.text.insert("insert", "\n")
 | 
				
			||||||
 | 
					            self.text.see("insert")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.auto.auto_indent(event)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def enter_callback(self, event):
 | 
				
			||||||
 | 
					        if self.executing and not self.reading:
 | 
				
			||||||
 | 
					            return # Let the default binding (insert '\n') take over
 | 
				
			||||||
 | 
					        # If some text is selected, recall the selection
 | 
				
			||||||
 | 
					        # (but only if this before the I/O mark)
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            sel = self.text.get("sel.first", "sel.last")
 | 
				
			||||||
 | 
					            if sel:
 | 
				
			||||||
 | 
					                if self.text.compare("sel.last", "<=", "iomark"):
 | 
				
			||||||
 | 
					                    self.recall(sel)
 | 
				
			||||||
 | 
					                    return "break"
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        # If we're strictly before the line containing iomark, recall
 | 
				
			||||||
 | 
					        # the current line, less a leading prompt, less leading or
 | 
				
			||||||
 | 
					        # trailing whitespace
 | 
				
			||||||
 | 
					        if self.text.compare("insert", "<", "iomark linestart"):
 | 
				
			||||||
 | 
					            # Check if there's a relevant stdin range -- if so, use it
 | 
				
			||||||
 | 
					            prev = self.text.tag_prevrange("stdin", "insert")
 | 
				
			||||||
 | 
					            if prev and self.text.compare("insert", "<", prev[1]):
 | 
				
			||||||
 | 
					                self.recall(self.text.get(prev[0], prev[1]))
 | 
				
			||||||
 | 
					                return "break"
 | 
				
			||||||
 | 
					            next = self.text.tag_nextrange("stdin", "insert")
 | 
				
			||||||
 | 
					            if next and self.text.compare("insert lineend", ">=", next[0]):
 | 
				
			||||||
 | 
					                self.recall(self.text.get(next[0], next[1]))
 | 
				
			||||||
 | 
					                return "break"
 | 
				
			||||||
 | 
					            # No stdin mark -- just get the current line
 | 
				
			||||||
 | 
					            self.recall(self.text.get("insert linestart", "insert lineend"))
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					        # If we're in the current input and there's only whitespace
 | 
				
			||||||
 | 
					        # beyond the cursor, erase that whitespace first
 | 
				
			||||||
 | 
					        s = self.text.get("insert", "end-1c")
 | 
				
			||||||
 | 
					        if s and not string.strip(s):
 | 
				
			||||||
 | 
					            self.text.delete("insert", "end-1c")
 | 
				
			||||||
 | 
					        # If we're in the current input before its last line,
 | 
				
			||||||
 | 
					        # insert a newline right at the insert point
 | 
				
			||||||
 | 
					        if self.text.compare("insert", "<", "end-1c linestart"):
 | 
				
			||||||
 | 
					            self.auto.auto_indent(event)
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					        # We're in the last line; append a newline and submit it
 | 
				
			||||||
 | 
					        self.text.mark_set("insert", "end-1c")
 | 
				
			||||||
 | 
					        if self.reading:
 | 
				
			||||||
 | 
					            self.text.insert("insert", "\n")
 | 
				
			||||||
 | 
					            self.text.see("insert")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.auto.auto_indent(event)
 | 
				
			||||||
 | 
					        self.text.tag_add("stdin", "iomark", "end-1c")
 | 
				
			||||||
 | 
					        self.text.update_idletasks()
 | 
				
			||||||
 | 
					        if self.reading:
 | 
				
			||||||
 | 
					            self.top.quit() # Break out of recursive mainloop() in raw_input()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.runit()
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def recall(self, s):
 | 
				
			||||||
 | 
					        if self.history:
 | 
				
			||||||
 | 
					            self.history.recall(s)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def runit(self):
 | 
				
			||||||
 | 
					        line = self.text.get("iomark", "end-1c")
 | 
				
			||||||
 | 
					        # Strip off last newline and surrounding whitespace.
 | 
				
			||||||
 | 
					        # (To allow you to hit return twice to end a statement.)
 | 
				
			||||||
 | 
					        i = len(line)
 | 
				
			||||||
 | 
					        while i > 0 and line[i-1] in " \t":
 | 
				
			||||||
 | 
					            i = i-1
 | 
				
			||||||
 | 
					        if i > 0 and line[i-1] == "\n":
 | 
				
			||||||
 | 
					            i = i-1
 | 
				
			||||||
 | 
					        while i > 0 and line[i-1] in " \t":
 | 
				
			||||||
 | 
					            i = i-1
 | 
				
			||||||
 | 
					        line = line[:i]
 | 
				
			||||||
 | 
					        more = self.interp.runsource(line)
 | 
				
			||||||
 | 
					        if not more:
 | 
				
			||||||
 | 
					            self.showprompt()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def cancel_check(self, frame, what, args,
 | 
				
			||||||
 | 
					                     dooneevent=tkinter.dooneevent,
 | 
				
			||||||
 | 
					                     dontwait=tkinter.DONT_WAIT):
 | 
				
			||||||
 | 
					        # Hack -- use the debugger hooks to be able to handle events
 | 
				
			||||||
 | 
					        # and interrupt execution at any time.
 | 
				
			||||||
 | 
					        # This slows execution down quite a bit, so you may want to
 | 
				
			||||||
 | 
					        # disable this (by not calling settrace() in runcode() above)
 | 
				
			||||||
 | 
					        # for full-bore (uninterruptable) speed.
 | 
				
			||||||
 | 
					        # XXX This should become a user option.
 | 
				
			||||||
 | 
					        if self.canceled:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        dooneevent(dontwait)
 | 
				
			||||||
 | 
					        if self.canceled:
 | 
				
			||||||
 | 
					            self.canceled = 0
 | 
				
			||||||
 | 
					            raise KeyboardInterrupt
 | 
				
			||||||
 | 
					        return self._cancel_check
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def open_stack_viewer(self, event=None):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            sys.last_traceback
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            tkMessageBox.showerror("No stack trace",
 | 
				
			||||||
 | 
					                "There is no stack trace yet.\n"
 | 
				
			||||||
 | 
					                "(sys.last_traceback is not defined)",
 | 
				
			||||||
 | 
					                master=self.text)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        from StackViewer import StackBrowser
 | 
				
			||||||
 | 
					        sv = StackBrowser(self.root, self.flist)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def showprompt(self):
 | 
				
			||||||
 | 
					        self.resetoutput()
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            s = str(sys.ps1)
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            s = ""
 | 
				
			||||||
 | 
					        self.console.write(s)
 | 
				
			||||||
 | 
					        self.text.mark_set("insert", "end-1c")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def resetoutput(self):
 | 
				
			||||||
 | 
					        source = self.text.get("iomark", "end-1c")
 | 
				
			||||||
 | 
					        if self.history:
 | 
				
			||||||
 | 
					            self.history.history_store(source)
 | 
				
			||||||
 | 
					        if self.text.get("end-2c") != "\n":
 | 
				
			||||||
 | 
					            self.text.insert("end-1c", "\n")
 | 
				
			||||||
 | 
					        self.text.mark_set("iomark", "end-1c")
 | 
				
			||||||
 | 
					        sys.stdout.softspace = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def write(self, s, tags=()):
 | 
				
			||||||
 | 
					        self.text.mark_gravity("iomark", "right")
 | 
				
			||||||
 | 
					        OutputWindow.write(self, s, tags, "iomark")
 | 
				
			||||||
 | 
					        self.text.mark_gravity("iomark", "left")
 | 
				
			||||||
 | 
					        if self.canceled:
 | 
				
			||||||
 | 
					            self.canceled = 0
 | 
				
			||||||
 | 
					            raise KeyboardInterrupt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class PseudoFile:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, shell, tags):
 | 
				
			||||||
 | 
					        self.shell = shell
 | 
				
			||||||
 | 
					        self.tags = tags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def write(self, s):
 | 
				
			||||||
 | 
					        self.shell.write(s, self.tags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def writelines(self, l):
 | 
				
			||||||
 | 
					        map(self.write, l)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def flush(self):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def isatty(self):
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					usage_msg = """\
 | 
				
			||||||
 | 
					usage: idle.py [-c command] [-d] [-e] [-s] [-t title] [arg] ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					-c command  run this command
 | 
				
			||||||
 | 
					-d          enable debugger
 | 
				
			||||||
 | 
					-e          edit mode; arguments are files to be edited
 | 
				
			||||||
 | 
					-s          run $IDLESTARTUP or $PYTHONSTARTUP before anything else
 | 
				
			||||||
 | 
					-t title    set title of shell window
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					When neither -c nor -e is used, and there are arguments, and the first
 | 
				
			||||||
 | 
					argument is not '-', the first argument is run as a script.  Remaining
 | 
				
			||||||
 | 
					arguments are arguments to the script or to the command run by -c.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class usageError:
 | 
				
			||||||
 | 
					    def __init__(self, string): self.string = string
 | 
				
			||||||
 | 
					    def __repr__(self): return self.string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class main:
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.server = protocol.Server(connection_hook = self.address_ok)
 | 
				
			||||||
 | 
					            protocol.publish( 'IDLE', self.connect )
 | 
				
			||||||
 | 
					            self.main( sys.argv[1:] )
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        except protocol.connectionLost:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                client = protocol.Client()
 | 
				
			||||||
 | 
					                IDLE = client.getobject('IDLE')
 | 
				
			||||||
 | 
					                if IDLE:
 | 
				
			||||||
 | 
					                    try:
 | 
				
			||||||
 | 
					                        IDLE.remote( sys.argv[1:] )
 | 
				
			||||||
 | 
					                    except usageError, msg:
 | 
				
			||||||
 | 
					                        sys.stderr.write("Error: %s\n" % str(msg))
 | 
				
			||||||
 | 
					                        sys.stderr.write(usage_msg)
 | 
				
			||||||
 | 
					                    return
 | 
				
			||||||
 | 
					            except protocol.connectionLost:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # xxx Should scream via Tk()
 | 
				
			||||||
 | 
					        print "Something already has our socket, but it won't open a window for me!"
 | 
				
			||||||
 | 
					        print "Unable to proceed."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def idle(self):
 | 
				
			||||||
 | 
					        spawn.kill_zombies()
 | 
				
			||||||
 | 
					        self.server.rpc_loop()
 | 
				
			||||||
 | 
					        root.after(25, self.idle)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # We permit connections from localhost only
 | 
				
			||||||
 | 
					    def address_ok(self, addr):
 | 
				
			||||||
 | 
					        return addr[0] == '127.0.0.1'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def connect(self, client, addr):
 | 
				
			||||||
 | 
					        return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def remote( self, argv ):
 | 
				
			||||||
 | 
					        # xxx Should make this behavior match the behavior in main, or redo
 | 
				
			||||||
 | 
					        #     command line options entirely.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            opts, args = getopt.getopt(argv, "c:deist:")
 | 
				
			||||||
 | 
					        except getopt.error, msg:
 | 
				
			||||||
 | 
					            raise usageError(msg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        for filename in args:
 | 
				
			||||||
 | 
					            flist.open(filename)
 | 
				
			||||||
 | 
					        if not args:
 | 
				
			||||||
 | 
					            flist.new()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def main( self, argv ):
 | 
				
			||||||
 | 
					        cmd = None
 | 
				
			||||||
 | 
					        edit = 0
 | 
				
			||||||
 | 
					        noshell = 1
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        debug = 0
 | 
				
			||||||
 | 
					        startup = 0
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            opts, args = getopt.getopt(argv, "c:deist:")
 | 
				
			||||||
 | 
					        except getopt.error, msg:
 | 
				
			||||||
 | 
					            sys.stderr.write("Error: %s\n" % str(msg))
 | 
				
			||||||
 | 
					            sys.stderr.write(usage_msg)
 | 
				
			||||||
 | 
					            sys.exit(2)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        for o, a in opts:
 | 
				
			||||||
 | 
					            noshell = 0
 | 
				
			||||||
 | 
					            if o == '-c':
 | 
				
			||||||
 | 
					                cmd = a
 | 
				
			||||||
 | 
					            if o == '-d':
 | 
				
			||||||
 | 
					                debug = 1
 | 
				
			||||||
 | 
					            if o == '-e':
 | 
				
			||||||
 | 
					                edit = 1
 | 
				
			||||||
 | 
					            if o == '-s':
 | 
				
			||||||
 | 
					                startup = 1
 | 
				
			||||||
 | 
					            if o == '-t':
 | 
				
			||||||
 | 
					                PyShell.shell_title = a
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        if noshell: edit=1
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        if not edit:
 | 
				
			||||||
 | 
					            if cmd:
 | 
				
			||||||
 | 
					                sys.argv = ["-c"] + args
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                sys.argv = args or [""]
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        for i in range(len(sys.path)):
 | 
				
			||||||
 | 
					            sys.path[i] = os.path.abspath(sys.path[i])
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        pathx = []
 | 
				
			||||||
 | 
					        if edit:
 | 
				
			||||||
 | 
					            for filename in args:
 | 
				
			||||||
 | 
					                pathx.append(os.path.dirname(filename))
 | 
				
			||||||
 | 
					        elif args and args[0] != "-":
 | 
				
			||||||
 | 
					            pathx.append(os.path.dirname(args[0]))
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            pathx.append(os.curdir)
 | 
				
			||||||
 | 
					        for dir in pathx:
 | 
				
			||||||
 | 
					            dir = os.path.abspath(dir)
 | 
				
			||||||
 | 
					            if not dir in sys.path:
 | 
				
			||||||
 | 
					                sys.path.insert(0, dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        global flist, root
 | 
				
			||||||
 | 
					        root = Tk()
 | 
				
			||||||
 | 
					        fixwordbreaks(root)
 | 
				
			||||||
 | 
					        root.withdraw()
 | 
				
			||||||
 | 
					        flist = PyShellFileList(root)
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        if edit:
 | 
				
			||||||
 | 
					            for filename in args:
 | 
				
			||||||
 | 
					                flist.open(filename)
 | 
				
			||||||
 | 
					            if not args:
 | 
				
			||||||
 | 
					                flist.new()
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        #dbg=OnDemandOutputWindow(flist)
 | 
				
			||||||
 | 
					        #dbg.set_title('Internal IDLE Problem')
 | 
				
			||||||
 | 
					        #sys.stdout = PseudoFile(dbg,['stdout'])
 | 
				
			||||||
 | 
					        #sys.stderr = PseudoFile(dbg,['stderr'])
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					        if noshell:
 | 
				
			||||||
 | 
					          flist.pyshell = None
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					          shell = PyShell(flist)
 | 
				
			||||||
 | 
					          interp = shell.interp
 | 
				
			||||||
 | 
					          flist.pyshell = shell
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					          if startup:
 | 
				
			||||||
 | 
					              filename = os.environ.get("IDLESTARTUP") or \
 | 
				
			||||||
 | 
					                         os.environ.get("PYTHONSTARTUP")
 | 
				
			||||||
 | 
					              if filename and os.path.isfile(filename):
 | 
				
			||||||
 | 
					                  interp.execfile(filename)
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					          if debug:
 | 
				
			||||||
 | 
					              shell.open_debugger()
 | 
				
			||||||
 | 
					          if cmd:
 | 
				
			||||||
 | 
					              interp.execsource(cmd)
 | 
				
			||||||
 | 
					          elif not edit and args and args[0] != "-":
 | 
				
			||||||
 | 
					              interp.execfile(args[0])
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					          shell.begin()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.idle()
 | 
				
			||||||
 | 
					        root.mainloop()
 | 
				
			||||||
 | 
					        root.destroy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										121
									
								
								Lib/idlelib/README.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								Lib/idlelib/README.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,121 @@
 | 
				
			||||||
 | 
					EXPERIMENTAL LOADER IDLE 2000-05-29
 | 
				
			||||||
 | 
					-----------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   David Scherer  <dscherer@cmu.edu>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This is a modification of the CVS version of IDLE 0.5, updated as of
 | 
				
			||||||
 | 
					2000-03-09.  It is alpha software and might be unstable.  If it breaks,
 | 
				
			||||||
 | 
					you get to keep both pieces.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you have problems or suggestions, you should either contact me or
 | 
				
			||||||
 | 
					post to the list at http://www.python.org/mailman/listinfo/idle-dev
 | 
				
			||||||
 | 
					(making it clear that you are using this modified version of IDLE).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Changes:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The ExecBinding module, a replacement for ScriptBinding, executes
 | 
				
			||||||
 | 
					  programs in a separate process, piping standard I/O through an RPC
 | 
				
			||||||
 | 
					  mechanism to an OnDemandOutputWindow in IDLE.  It supports executing
 | 
				
			||||||
 | 
					  unnamed programs (through a temporary file).  It does not yet support
 | 
				
			||||||
 | 
					  debugging.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  When running programs with ExecBinding, tracebacks will be clipped
 | 
				
			||||||
 | 
					  to exclude system modules.  If, however, a system module calls back
 | 
				
			||||||
 | 
					  into the user program, that part of the traceback will be shown.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The OnDemandOutputWindow class has been improved.  In particular,
 | 
				
			||||||
 | 
					  it now supports a readline() function used to implement user input,
 | 
				
			||||||
 | 
					  and a scroll_clear() operation which is used to hide the output of
 | 
				
			||||||
 | 
					  a previous run by scrolling it out of the window.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Startup behavior has been changed.  By default IDLE starts up with
 | 
				
			||||||
 | 
					  just a blank editor window, rather than an interactive window.  Opening
 | 
				
			||||||
 | 
					  a file in such a blank window replaces the (nonexistent) contents of
 | 
				
			||||||
 | 
					  that window instead of creating another window.  Because of the need to
 | 
				
			||||||
 | 
					  have a well-known port for the ExecBinding protocol, only one copy of
 | 
				
			||||||
 | 
					  IDLE can be running.  Additional invocations use the RPC mechanism to
 | 
				
			||||||
 | 
					  report their command line arguments to the copy already running.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  The menus have been reorganized.  In particular, the excessively large
 | 
				
			||||||
 | 
					  'edit' menu has been split up into 'edit', 'format', and 'run'.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  'Python Documentation' now works on Windows, if the win32api module is
 | 
				
			||||||
 | 
					  present.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  A few key bindings have been changed: F1 now loads Python Documentation
 | 
				
			||||||
 | 
					  instead of the IDLE help; shift-TAB is now a synonym for unindent.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					New modules:
 | 
				
			||||||
 | 
					  ExecBinding.py         Executes program through loader
 | 
				
			||||||
 | 
					  loader.py              Bootstraps user program
 | 
				
			||||||
 | 
					  protocol.py            RPC protocol
 | 
				
			||||||
 | 
					  Remote.py              User-process interpreter
 | 
				
			||||||
 | 
					  spawn.py               OS-specific code to start programs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Files modified:
 | 
				
			||||||
 | 
					  autoindent.py          ( bindings tweaked )
 | 
				
			||||||
 | 
					  bindings.py            ( menus reorganized )
 | 
				
			||||||
 | 
					  config.txt             ( execbinding enabled )
 | 
				
			||||||
 | 
					  editorwindow.py        ( new menus, fixed 'Python Documentation' )
 | 
				
			||||||
 | 
					  filelist.py            ( hook for "open in same window" )
 | 
				
			||||||
 | 
					  formatparagraph.py     ( bindings tweaked )
 | 
				
			||||||
 | 
					  idle.bat               ( removed absolute pathname )
 | 
				
			||||||
 | 
					  idle.pyw               ( weird bug due to import with same name? )
 | 
				
			||||||
 | 
					  iobinding.py           ( open in same window, EOL convention )
 | 
				
			||||||
 | 
					  keydefs.py             ( bindings tweaked )
 | 
				
			||||||
 | 
					  outputwindow.py        ( readline, scroll_clear, etc )
 | 
				
			||||||
 | 
					  pyshell.py             ( changed startup behavior )
 | 
				
			||||||
 | 
					  readme.txt             ( <Recursion on file with id=1234567> )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IDLE 0.5 - February 2000
 | 
				
			||||||
 | 
					------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This is an early release of IDLE, my own attempt at a Tkinter-based
 | 
				
			||||||
 | 
					IDE for Python.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For news about this release, see the file NEWS.txt.  (For a more
 | 
				
			||||||
 | 
					detailed change log, see the file ChangeLog.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FEATURES
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IDLE has the following features:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- coded in 100% pure Python, using the Tkinter GUI toolkit (i.e. Tcl/Tk)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- cross-platform: works on Windows and Unix (on the Mac, there are
 | 
				
			||||||
 | 
					currently problems with Tcl/Tk)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- multi-window text editor with multiple undo, Python colorizing
 | 
				
			||||||
 | 
					and many other features, e.g. smart indent and call tips
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Python shell window (a.k.a. interactive interpreter)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- debugger (not complete, but you can set breakpoints, view  and step)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					USAGE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The main program is in the file "idle.py"; on Unix, you should be able
 | 
				
			||||||
 | 
					to run it by typing "./idle.py" to your shell.  On Windows, you can
 | 
				
			||||||
 | 
					run it by double-clicking it; you can use idle.pyw to avoid popping up
 | 
				
			||||||
 | 
					a DOS console.  If you want to pass command line arguments on Windows,
 | 
				
			||||||
 | 
					use the batch file idle.bat.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Command line arguments: files passed on the command line are executed,
 | 
				
			||||||
 | 
					not opened for editing, unless you give the -e command line option.
 | 
				
			||||||
 | 
					Try "./idle.py -h" to see other command line options.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IDLE requires Python 1.5.2, so it is currently only usable with a
 | 
				
			||||||
 | 
					Python 1.5.2 distribution.  (An older version of IDLE is distributed
 | 
				
			||||||
 | 
					with Python 1.5.2; you can drop this version on top of it.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					COPYRIGHT
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					IDLE is covered by the standard Python copyright notice
 | 
				
			||||||
 | 
					(http://www.python.org/doc/Copyright.html).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					FEEDBACK
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(removed, since Guido probably doesn't want complaints about my
 | 
				
			||||||
 | 
					changes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					--Guido van Rossum (home page: http://www.python.org/~guido/)
 | 
				
			||||||
							
								
								
									
										101
									
								
								Lib/idlelib/Remote.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								Lib/idlelib/Remote.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,101 @@
 | 
				
			||||||
 | 
					"""Remote
 | 
				
			||||||
 | 
					     This module is imported by the loader and serves to control
 | 
				
			||||||
 | 
					     the execution of the user program.  It presently executes files
 | 
				
			||||||
 | 
					     and reports exceptions to IDLE.  It could be extended to provide
 | 
				
			||||||
 | 
					     other services, such as interactive mode and debugging.  To that
 | 
				
			||||||
 | 
					     end, it could be a subclass of e.g. InteractiveInterpreter.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     Two other classes, pseudoIn and pseudoOut, are file emulators also
 | 
				
			||||||
 | 
					     used by loader.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					import sys, os
 | 
				
			||||||
 | 
					import traceback
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Remote:    
 | 
				
			||||||
 | 
					    def __init__(self, main, master):
 | 
				
			||||||
 | 
					        self.main = main
 | 
				
			||||||
 | 
					        self.master = master
 | 
				
			||||||
 | 
					        self.this_file = self.canonic( self.__init__.im_func.func_code.co_filename )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def canonic(self, path):
 | 
				
			||||||
 | 
					        return os.path.normcase(os.path.abspath(path))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def mainloop(self):
 | 
				
			||||||
 | 
					        while 1:
 | 
				
			||||||
 | 
					            args = self.master.get_command()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                f = getattr(self,args[0])
 | 
				
			||||||
 | 
					                apply(f,args[1:])
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                if not self.report_exception(): raise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def finish(self):
 | 
				
			||||||
 | 
					        sys.exit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run(self, *argv):
 | 
				
			||||||
 | 
					        sys.argv = argv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        path = self.canonic( argv[0] )
 | 
				
			||||||
 | 
					        dir = self.dir = os.path.dirname(path)
 | 
				
			||||||
 | 
					        os.chdir(dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        sys.path[0] = dir
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        usercode = open(path)
 | 
				
			||||||
 | 
					        exec usercode in self.main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def report_exception(self):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            type, value, tb = sys.exc_info()
 | 
				
			||||||
 | 
					            sys.last_type = type
 | 
				
			||||||
 | 
					            sys.last_value = value
 | 
				
			||||||
 | 
					            sys.last_traceback = tb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            tblist = traceback.extract_tb(tb)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Look through the traceback, canonicalizing filenames and
 | 
				
			||||||
 | 
					            #   eliminating leading and trailing system modules.
 | 
				
			||||||
 | 
					            first = last = 1
 | 
				
			||||||
 | 
					            for i in range(len(tblist)):
 | 
				
			||||||
 | 
					                filename, lineno, name, line = tblist[i]
 | 
				
			||||||
 | 
					                filename = self.canonic(filename)
 | 
				
			||||||
 | 
					                tblist[i] = filename, lineno, name, line
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                dir = os.path.dirname(filename)
 | 
				
			||||||
 | 
					                if filename == self.this_file:
 | 
				
			||||||
 | 
					                    first = i+1
 | 
				
			||||||
 | 
					                elif dir==self.dir:
 | 
				
			||||||
 | 
					                    last = i+1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            # Canonicalize the filename in a syntax error, too:
 | 
				
			||||||
 | 
					            if type is SyntaxError:
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    msg, (filename, lineno, offset, line) = value
 | 
				
			||||||
 | 
					                    filename = self.canonic(filename)
 | 
				
			||||||
 | 
					                    value = msg, (filename, lineno, offset, line)
 | 
				
			||||||
 | 
					                except:
 | 
				
			||||||
 | 
					                    pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return self.master.program_exception( type, value, tblist, first, last )
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            # avoid any circular reference through the traceback
 | 
				
			||||||
 | 
					            del tb
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class pseudoIn:
 | 
				
			||||||
 | 
					    def __init__(self, readline):
 | 
				
			||||||
 | 
					        self.readline = readline
 | 
				
			||||||
 | 
					    def isatty():
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class pseudoOut:
 | 
				
			||||||
 | 
					    def __init__(self, func, **kw):
 | 
				
			||||||
 | 
					        self.func = func
 | 
				
			||||||
 | 
					        self.kw = kw
 | 
				
			||||||
 | 
					    def write(self, *args):
 | 
				
			||||||
 | 
					        return apply( self.func, args, self.kw )
 | 
				
			||||||
 | 
					    def writelines(self, l):
 | 
				
			||||||
 | 
					        map(self.write, l)
 | 
				
			||||||
 | 
					    def flush(self):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										172
									
								
								Lib/idlelib/ReplaceDialog.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								Lib/idlelib/ReplaceDialog.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,172 @@
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import fnmatch
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					import tkMessageBox
 | 
				
			||||||
 | 
					import SearchEngine
 | 
				
			||||||
 | 
					from SearchDialogBase import SearchDialogBase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def replace(text):
 | 
				
			||||||
 | 
					    root = text._root()
 | 
				
			||||||
 | 
					    engine = SearchEngine.get(root)
 | 
				
			||||||
 | 
					    if not hasattr(engine, "_replacedialog"):
 | 
				
			||||||
 | 
					        engine._replacedialog = ReplaceDialog(root, engine)
 | 
				
			||||||
 | 
					    dialog = engine._replacedialog
 | 
				
			||||||
 | 
					    dialog.open(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ReplaceDialog(SearchDialogBase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    title = "Replace Dialog"
 | 
				
			||||||
 | 
					    icon = "Replace"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, root, engine):
 | 
				
			||||||
 | 
					        SearchDialogBase.__init__(self, root, engine)
 | 
				
			||||||
 | 
					        self.replvar = StringVar(root)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def open(self, text):
 | 
				
			||||||
 | 
					        SearchDialogBase.open(self, text)
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            first = text.index("sel.first")
 | 
				
			||||||
 | 
					        except TclError:
 | 
				
			||||||
 | 
					            first = None
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            last = text.index("sel.last")
 | 
				
			||||||
 | 
					        except TclError:
 | 
				
			||||||
 | 
					            last = None
 | 
				
			||||||
 | 
					        first = first or text.index("insert")
 | 
				
			||||||
 | 
					        last = last or first
 | 
				
			||||||
 | 
					        self.show_hit(first, last)
 | 
				
			||||||
 | 
					        self.ok = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_entries(self):
 | 
				
			||||||
 | 
					        SearchDialogBase.create_entries(self)
 | 
				
			||||||
 | 
					        self.replent = self.make_entry("Replace with:", self.replvar)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_command_buttons(self):
 | 
				
			||||||
 | 
					        SearchDialogBase.create_command_buttons(self)
 | 
				
			||||||
 | 
					        self.make_button("Find", self.find_it)
 | 
				
			||||||
 | 
					        self.make_button("Replace", self.replace_it)
 | 
				
			||||||
 | 
					        self.make_button("Replace+Find", self.default_command, 1)
 | 
				
			||||||
 | 
					        self.make_button("Replace All", self.replace_all)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def find_it(self, event=None):
 | 
				
			||||||
 | 
					        self.do_find(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def replace_it(self, event=None):
 | 
				
			||||||
 | 
					        if self.do_find(self.ok):
 | 
				
			||||||
 | 
					            self.do_replace()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def default_command(self, event=None):
 | 
				
			||||||
 | 
					        if self.do_find(self.ok):
 | 
				
			||||||
 | 
					            self.do_replace()
 | 
				
			||||||
 | 
					            self.do_find(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def replace_all(self, event=None):
 | 
				
			||||||
 | 
					        prog = self.engine.getprog()
 | 
				
			||||||
 | 
					        if not prog:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        repl = self.replvar.get()
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        res = self.engine.search_text(text, prog)
 | 
				
			||||||
 | 
					        if not res:
 | 
				
			||||||
 | 
					            text.bell()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        text.tag_remove("sel", "1.0", "end")
 | 
				
			||||||
 | 
					        text.tag_remove("hit", "1.0", "end")
 | 
				
			||||||
 | 
					        line = res[0]
 | 
				
			||||||
 | 
					        col = res[1].start()
 | 
				
			||||||
 | 
					        if self.engine.iswrap():
 | 
				
			||||||
 | 
					            line = 1
 | 
				
			||||||
 | 
					            col = 0
 | 
				
			||||||
 | 
					        ok = 1
 | 
				
			||||||
 | 
					        first = last = None
 | 
				
			||||||
 | 
					        # XXX ought to replace circular instead of top-to-bottom when wrapping
 | 
				
			||||||
 | 
					        text.undo_block_start()
 | 
				
			||||||
 | 
					        while 1:
 | 
				
			||||||
 | 
					            res = self.engine.search_forward(text, prog, line, col, 0, ok)
 | 
				
			||||||
 | 
					            if not res:
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            line, m = res
 | 
				
			||||||
 | 
					            chars = text.get("%d.0" % line, "%d.0" % (line+1))
 | 
				
			||||||
 | 
					            orig = m.group()
 | 
				
			||||||
 | 
					            new = re.pcre_expand(m, repl)
 | 
				
			||||||
 | 
					            i, j = m.span()
 | 
				
			||||||
 | 
					            first = "%d.%d" % (line, i)
 | 
				
			||||||
 | 
					            last = "%d.%d" % (line, j)
 | 
				
			||||||
 | 
					            if new == orig:
 | 
				
			||||||
 | 
					                text.mark_set("insert", last)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                text.mark_set("insert", first)
 | 
				
			||||||
 | 
					                if first != last:
 | 
				
			||||||
 | 
					                    text.delete(first, last)
 | 
				
			||||||
 | 
					                if new:
 | 
				
			||||||
 | 
					                    text.insert(first, new)
 | 
				
			||||||
 | 
					            col = i + len(new)
 | 
				
			||||||
 | 
					            ok = 0
 | 
				
			||||||
 | 
					        text.undo_block_stop()
 | 
				
			||||||
 | 
					        if first and last:
 | 
				
			||||||
 | 
					            self.show_hit(first, last)
 | 
				
			||||||
 | 
					        self.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def do_find(self, ok=0):
 | 
				
			||||||
 | 
					        if not self.engine.getprog():
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        res = self.engine.search_text(text, None, ok)
 | 
				
			||||||
 | 
					        if not res:
 | 
				
			||||||
 | 
					            text.bell()
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        line, m = res
 | 
				
			||||||
 | 
					        i, j = m.span()
 | 
				
			||||||
 | 
					        first = "%d.%d" % (line, i)
 | 
				
			||||||
 | 
					        last = "%d.%d" % (line, j)
 | 
				
			||||||
 | 
					        self.show_hit(first, last)
 | 
				
			||||||
 | 
					        self.ok = 1
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def do_replace(self):
 | 
				
			||||||
 | 
					        prog = self.engine.getprog()
 | 
				
			||||||
 | 
					        if not prog:
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            first = pos = text.index("sel.first")
 | 
				
			||||||
 | 
					            last = text.index("sel.last")
 | 
				
			||||||
 | 
					        except TclError:
 | 
				
			||||||
 | 
					            pos = None
 | 
				
			||||||
 | 
					        if not pos:
 | 
				
			||||||
 | 
					            first = last = pos = text.index("insert")
 | 
				
			||||||
 | 
					        line, col = SearchEngine.get_line_col(pos)
 | 
				
			||||||
 | 
					        chars = text.get("%d.0" % line, "%d.0" % (line+1))
 | 
				
			||||||
 | 
					        m = prog.match(chars, col)
 | 
				
			||||||
 | 
					        if not prog:
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        new = re.pcre_expand(m, self.replvar.get())
 | 
				
			||||||
 | 
					        text.mark_set("insert", first)
 | 
				
			||||||
 | 
					        text.undo_block_start()
 | 
				
			||||||
 | 
					        if m.group():
 | 
				
			||||||
 | 
					            text.delete(first, last)
 | 
				
			||||||
 | 
					        if new:
 | 
				
			||||||
 | 
					            text.insert(first, new)
 | 
				
			||||||
 | 
					        text.undo_block_stop()
 | 
				
			||||||
 | 
					        self.show_hit(first, text.index("insert"))
 | 
				
			||||||
 | 
					        self.ok = 0
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def show_hit(self, first, last):
 | 
				
			||||||
 | 
					        text = self.text
 | 
				
			||||||
 | 
					        text.mark_set("insert", first)
 | 
				
			||||||
 | 
					        text.tag_remove("sel", "1.0", "end")
 | 
				
			||||||
 | 
					        text.tag_add("sel", first, last)
 | 
				
			||||||
 | 
					        text.tag_remove("hit", "1.0", "end")
 | 
				
			||||||
 | 
					        if first == last:
 | 
				
			||||||
 | 
					            text.tag_add("hit", first)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            text.tag_add("hit", first, last)
 | 
				
			||||||
 | 
					        text.see("insert")
 | 
				
			||||||
 | 
					        text.update_idletasks()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self, event=None):
 | 
				
			||||||
 | 
					        SearchDialogBase.close(self, event)
 | 
				
			||||||
 | 
					        self.text.tag_remove("hit", "1.0", "end")
 | 
				
			||||||
							
								
								
									
										169
									
								
								Lib/idlelib/ScriptBinding.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								Lib/idlelib/ScriptBinding.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,169 @@
 | 
				
			||||||
 | 
					"""Extension to execute code outside the Python shell window.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This adds the following commands (to the Edit menu, until there's a
 | 
				
			||||||
 | 
					separate Python menu):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Check module (Alt-F5) does a full syntax check of the current module.
 | 
				
			||||||
 | 
					It also runs the tabnanny to catch any inconsistent tabs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Import module (F5) is equivalent to either import or reload of the
 | 
				
			||||||
 | 
					current module.  The window must have been saved previously. The
 | 
				
			||||||
 | 
					module is added to sys.modules, and is also added to the __main__
 | 
				
			||||||
 | 
					namespace.  Output goes to the shell window.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Run module (Control-F5) does the same but executes the module's
 | 
				
			||||||
 | 
					code in the __main__ namespace.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import imp
 | 
				
			||||||
 | 
					import tkMessageBox
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					indent_message = """Error: Inconsistent indentation detected!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This means that either:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(1) your indentation is outright incorrect (easy to fix), or
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(2) your indentation mixes tabs and spaces in a way that depends on \
 | 
				
			||||||
 | 
					how many spaces a tab is worth.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To fix case 2, change all tabs to spaces by using Select All followed \
 | 
				
			||||||
 | 
					by Untabify Region (both in the Edit menu)."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ScriptBinding:
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    keydefs = {
 | 
				
			||||||
 | 
					        '<<check-module>>': ['<Alt-F5>', '<Meta-F5>'],
 | 
				
			||||||
 | 
					        '<<import-module>>': ['<F5>'],
 | 
				
			||||||
 | 
					        '<<run-script>>': ['<Control-F5>'],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    menudefs = [
 | 
				
			||||||
 | 
					        ('edit', [None,
 | 
				
			||||||
 | 
					                  ('Check module', '<<check-module>>'),
 | 
				
			||||||
 | 
					                  ('Import module', '<<import-module>>'),
 | 
				
			||||||
 | 
					                  ('Run script', '<<run-script>>'),
 | 
				
			||||||
 | 
					                 ]
 | 
				
			||||||
 | 
					        ),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, editwin):
 | 
				
			||||||
 | 
					        self.editwin = editwin
 | 
				
			||||||
 | 
					        # Provide instance variables referenced by Debugger
 | 
				
			||||||
 | 
					        # XXX This should be done differently
 | 
				
			||||||
 | 
					        self.flist = self.editwin.flist
 | 
				
			||||||
 | 
					        self.root = self.flist.root
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def check_module_event(self, event):
 | 
				
			||||||
 | 
					        filename = self.getfilename()
 | 
				
			||||||
 | 
					        if not filename:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if not self.tabnanny(filename):
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if not self.checksyntax(filename):
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def tabnanny(self, filename):
 | 
				
			||||||
 | 
					        import tabnanny
 | 
				
			||||||
 | 
					        import tokenize
 | 
				
			||||||
 | 
					        tabnanny.reset_globals()
 | 
				
			||||||
 | 
					        f = open(filename, 'r')
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            tokenize.tokenize(f.readline, tabnanny.tokeneater)
 | 
				
			||||||
 | 
					        except tokenize.TokenError, msg:
 | 
				
			||||||
 | 
					            self.errorbox("Token error",
 | 
				
			||||||
 | 
					                          "Token error:\n%s" % str(msg))
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        except tabnanny.NannyNag, nag:
 | 
				
			||||||
 | 
					            # The error messages from tabnanny are too confusing...
 | 
				
			||||||
 | 
					            self.editwin.gotoline(nag.get_lineno())
 | 
				
			||||||
 | 
					            self.errorbox("Tab/space error", indent_message)
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def checksyntax(self, filename):
 | 
				
			||||||
 | 
					        f = open(filename, 'r')
 | 
				
			||||||
 | 
					        source = f.read()
 | 
				
			||||||
 | 
					        f.close()
 | 
				
			||||||
 | 
					        if '\r' in source:
 | 
				
			||||||
 | 
					            import re
 | 
				
			||||||
 | 
					            source = re.sub(r"\r\n", "\n", source)
 | 
				
			||||||
 | 
					        if source and source[-1] != '\n':
 | 
				
			||||||
 | 
					            source = source + '\n'
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            compile(source, filename, "exec")
 | 
				
			||||||
 | 
					        except (SyntaxError, OverflowError), err:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                msg, (errorfilename, lineno, offset, line) = err
 | 
				
			||||||
 | 
					                if not errorfilename:
 | 
				
			||||||
 | 
					                    err.args = msg, (filename, lineno, offset, line)
 | 
				
			||||||
 | 
					                    err.filename = filename
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                lineno = None
 | 
				
			||||||
 | 
					                msg = "*** " + str(err)
 | 
				
			||||||
 | 
					            if lineno:
 | 
				
			||||||
 | 
					                self.editwin.gotoline(lineno)
 | 
				
			||||||
 | 
					            self.errorbox("Syntax error",
 | 
				
			||||||
 | 
					                          "There's an error in your program:\n" + msg)
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def import_module_event(self, event):
 | 
				
			||||||
 | 
					        filename = self.getfilename()
 | 
				
			||||||
 | 
					        if not filename:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        modname, ext = os.path.splitext(os.path.basename(filename))
 | 
				
			||||||
 | 
					        if sys.modules.has_key(modname):
 | 
				
			||||||
 | 
					            mod = sys.modules[modname]
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            mod = imp.new_module(modname)
 | 
				
			||||||
 | 
					            sys.modules[modname] = mod
 | 
				
			||||||
 | 
					        mod.__file__ = filename
 | 
				
			||||||
 | 
					        setattr(sys.modules['__main__'], modname, mod)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        dir = os.path.dirname(filename)
 | 
				
			||||||
 | 
					        dir = os.path.normpath(os.path.abspath(dir))
 | 
				
			||||||
 | 
					        if dir not in sys.path:
 | 
				
			||||||
 | 
					            sys.path.insert(0, dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        flist = self.editwin.flist
 | 
				
			||||||
 | 
					        shell = flist.open_shell()
 | 
				
			||||||
 | 
					        interp = shell.interp
 | 
				
			||||||
 | 
					        interp.runcode("reload(%s)" % modname)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run_script_event(self, event):
 | 
				
			||||||
 | 
					        filename = self.getfilename()
 | 
				
			||||||
 | 
					        if not filename:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        flist = self.editwin.flist
 | 
				
			||||||
 | 
					        shell = flist.open_shell()
 | 
				
			||||||
 | 
					        interp = shell.interp
 | 
				
			||||||
 | 
					        if (not sys.argv or
 | 
				
			||||||
 | 
					            os.path.basename(sys.argv[0]) != os.path.basename(filename)):
 | 
				
			||||||
 | 
					            # XXX Too often this discards arguments the user just set...
 | 
				
			||||||
 | 
					            sys.argv = [filename]
 | 
				
			||||||
 | 
					        interp.execfile(filename)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getfilename(self):
 | 
				
			||||||
 | 
					        # Logic to make sure we have a saved filename
 | 
				
			||||||
 | 
					        # XXX Better logic would offer to save!
 | 
				
			||||||
 | 
					        if not self.editwin.get_saved():
 | 
				
			||||||
 | 
					            self.errorbox("Not saved",
 | 
				
			||||||
 | 
					                          "Please save first!")
 | 
				
			||||||
 | 
					            self.editwin.text.focus_set()
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        filename = self.editwin.io.filename
 | 
				
			||||||
 | 
					        if not filename:
 | 
				
			||||||
 | 
					            self.errorbox("No file name",
 | 
				
			||||||
 | 
					                          "This window has no file name")
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        return filename
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def errorbox(self, title, message):
 | 
				
			||||||
 | 
					        # XXX This should really be a function of EditorWindow...
 | 
				
			||||||
 | 
					        tkMessageBox.showerror(title, message, master=self.editwin.text)
 | 
				
			||||||
 | 
					        self.editwin.text.focus_set()
 | 
				
			||||||
							
								
								
									
										139
									
								
								Lib/idlelib/ScrolledList.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										139
									
								
								Lib/idlelib/ScrolledList.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,139 @@
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ScrolledList:
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    default = "(None)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, master, **options):
 | 
				
			||||||
 | 
					        # Create top frame, with scrollbar and listbox
 | 
				
			||||||
 | 
					        self.master = master
 | 
				
			||||||
 | 
					        self.frame = frame = Frame(master)
 | 
				
			||||||
 | 
					        self.frame.pack(fill="both", expand=1)
 | 
				
			||||||
 | 
					        self.vbar = vbar = Scrollbar(frame, name="vbar")
 | 
				
			||||||
 | 
					        self.vbar.pack(side="right", fill="y")
 | 
				
			||||||
 | 
					        self.listbox = listbox = Listbox(frame, exportselection=0,
 | 
				
			||||||
 | 
					            background="white")
 | 
				
			||||||
 | 
					        if options:
 | 
				
			||||||
 | 
					            listbox.configure(options)
 | 
				
			||||||
 | 
					        listbox.pack(expand=1, fill="both")
 | 
				
			||||||
 | 
					        # Tie listbox and scrollbar together
 | 
				
			||||||
 | 
					        vbar["command"] = listbox.yview
 | 
				
			||||||
 | 
					        listbox["yscrollcommand"] = vbar.set
 | 
				
			||||||
 | 
					        # Bind events to the list box
 | 
				
			||||||
 | 
					        listbox.bind("<ButtonRelease-1>", self.click_event)
 | 
				
			||||||
 | 
					        listbox.bind("<Double-ButtonRelease-1>", self.double_click_event)
 | 
				
			||||||
 | 
					        listbox.bind("<ButtonPress-3>", self.popup_event)
 | 
				
			||||||
 | 
					        listbox.bind("<Key-Up>", self.up_event)
 | 
				
			||||||
 | 
					        listbox.bind("<Key-Down>", self.down_event)
 | 
				
			||||||
 | 
					        # Mark as empty
 | 
				
			||||||
 | 
					        self.clear()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self):
 | 
				
			||||||
 | 
					        self.frame.destroy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def clear(self):
 | 
				
			||||||
 | 
					        self.listbox.delete(0, "end")
 | 
				
			||||||
 | 
					        self.empty = 1
 | 
				
			||||||
 | 
					        self.listbox.insert("end", self.default)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def append(self, item):
 | 
				
			||||||
 | 
					        if self.empty:
 | 
				
			||||||
 | 
					            self.listbox.delete(0, "end")
 | 
				
			||||||
 | 
					            self.empty = 0
 | 
				
			||||||
 | 
					        self.listbox.insert("end", str(item))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get(self, index):
 | 
				
			||||||
 | 
					        return self.listbox.get(index)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def click_event(self, event):
 | 
				
			||||||
 | 
					        self.listbox.activate("@%d,%d" % (event.x, event.y))
 | 
				
			||||||
 | 
					        index = self.listbox.index("active")
 | 
				
			||||||
 | 
					        self.select(index)
 | 
				
			||||||
 | 
					        self.on_select(index)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def double_click_event(self, event):
 | 
				
			||||||
 | 
					        index = self.listbox.index("active")
 | 
				
			||||||
 | 
					        self.select(index)
 | 
				
			||||||
 | 
					        self.on_double(index)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    menu = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def popup_event(self, event):
 | 
				
			||||||
 | 
					        if not self.menu:
 | 
				
			||||||
 | 
					            self.make_menu()
 | 
				
			||||||
 | 
					        menu = self.menu
 | 
				
			||||||
 | 
					        self.listbox.activate("@%d,%d" % (event.x, event.y))
 | 
				
			||||||
 | 
					        index = self.listbox.index("active")
 | 
				
			||||||
 | 
					        self.select(index)
 | 
				
			||||||
 | 
					        menu.tk_popup(event.x_root, event.y_root)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def make_menu(self):
 | 
				
			||||||
 | 
					        menu = Menu(self.listbox, tearoff=0)
 | 
				
			||||||
 | 
					        self.menu = menu
 | 
				
			||||||
 | 
					        self.fill_menu()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def up_event(self, event):
 | 
				
			||||||
 | 
					        index = self.listbox.index("active")
 | 
				
			||||||
 | 
					        if self.listbox.selection_includes(index):
 | 
				
			||||||
 | 
					            index = index - 1
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            index = self.listbox.size() - 1
 | 
				
			||||||
 | 
					        if index < 0:
 | 
				
			||||||
 | 
					            self.listbox.bell()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.select(index)
 | 
				
			||||||
 | 
					            self.on_select(index)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def down_event(self, event):
 | 
				
			||||||
 | 
					        index = self.listbox.index("active")
 | 
				
			||||||
 | 
					        if self.listbox.selection_includes(index):
 | 
				
			||||||
 | 
					            index = index + 1
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            index = 0
 | 
				
			||||||
 | 
					        if index >= self.listbox.size():
 | 
				
			||||||
 | 
					            self.listbox.bell()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.select(index)
 | 
				
			||||||
 | 
					            self.on_select(index)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def select(self, index):
 | 
				
			||||||
 | 
					        self.listbox.focus_set()
 | 
				
			||||||
 | 
					        self.listbox.activate(index)
 | 
				
			||||||
 | 
					        self.listbox.selection_clear(0, "end")
 | 
				
			||||||
 | 
					        self.listbox.selection_set(index)
 | 
				
			||||||
 | 
					        self.listbox.see(index)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Methods to override for specific actions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def fill_menu(self):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_select(self, index):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_double(self, index):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test():
 | 
				
			||||||
 | 
					    root = Tk()
 | 
				
			||||||
 | 
					    root.protocol("WM_DELETE_WINDOW", root.destroy)
 | 
				
			||||||
 | 
					    class MyScrolledList(ScrolledList):
 | 
				
			||||||
 | 
					        def fill_menu(self): self.menu.add_command(label="pass")
 | 
				
			||||||
 | 
					        def on_select(self, index): print "select", self.get(index)
 | 
				
			||||||
 | 
					        def on_double(self, index): print "double", self.get(index)
 | 
				
			||||||
 | 
					    s = MyScrolledList(root)
 | 
				
			||||||
 | 
					    for i in range(30):
 | 
				
			||||||
 | 
					        s.append("item %02d" % i)
 | 
				
			||||||
 | 
					    return root
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    root = test()
 | 
				
			||||||
 | 
					    root.mainloop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										97
									
								
								Lib/idlelib/SearchBinding.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								Lib/idlelib/SearchBinding.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,97 @@
 | 
				
			||||||
 | 
					import tkSimpleDialog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###$ event <<find>>
 | 
				
			||||||
 | 
					###$ win <Control-f>
 | 
				
			||||||
 | 
					###$ unix <Control-u><Control-u><Control-s>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###$ event <<find-again>>
 | 
				
			||||||
 | 
					###$ win <Control-g>
 | 
				
			||||||
 | 
					###$ win <F3>
 | 
				
			||||||
 | 
					###$ unix <Control-u><Control-s>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###$ event <<find-selection>>
 | 
				
			||||||
 | 
					###$ win <Control-F3>
 | 
				
			||||||
 | 
					###$ unix <Control-s>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###$ event <<find-in-files>>
 | 
				
			||||||
 | 
					###$ win <Alt-F3>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###$ event <<replace>>
 | 
				
			||||||
 | 
					###$ win <Control-h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					###$ event <<goto-line>>
 | 
				
			||||||
 | 
					###$ win <Alt-g>
 | 
				
			||||||
 | 
					###$ unix <Alt-g>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SearchBinding:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    windows_keydefs = {
 | 
				
			||||||
 | 
					        '<<find-again>>': ['<Control-g>', '<F3>'],
 | 
				
			||||||
 | 
					        '<<find-in-files>>': ['<Alt-F3>'],
 | 
				
			||||||
 | 
					        '<<find-selection>>': ['<Control-F3>'],
 | 
				
			||||||
 | 
					        '<<find>>': ['<Control-f>'],
 | 
				
			||||||
 | 
					        '<<replace>>': ['<Control-h>'],
 | 
				
			||||||
 | 
					        '<<goto-line>>': ['<Alt-g>'],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unix_keydefs = {
 | 
				
			||||||
 | 
					        '<<find-again>>': ['<Control-u><Control-s>'],
 | 
				
			||||||
 | 
					        '<<find-in-files>>': ['<Alt-s>', '<Meta-s>'],
 | 
				
			||||||
 | 
					        '<<find-selection>>': ['<Control-s>'],
 | 
				
			||||||
 | 
					        '<<find>>': ['<Control-u><Control-u><Control-s>'],
 | 
				
			||||||
 | 
					        '<<replace>>': ['<Control-r>'],
 | 
				
			||||||
 | 
					        '<<goto-line>>': ['<Alt-g>', '<Meta-g>'],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    menudefs = [
 | 
				
			||||||
 | 
					        ('edit', [
 | 
				
			||||||
 | 
					            None,
 | 
				
			||||||
 | 
					            ('_Find...', '<<find>>'),
 | 
				
			||||||
 | 
					            ('Find a_gain', '<<find-again>>'),
 | 
				
			||||||
 | 
					            ('Find _selection', '<<find-selection>>'),
 | 
				
			||||||
 | 
					            ('Find in Files...', '<<find-in-files>>'),
 | 
				
			||||||
 | 
					            ('R_eplace...', '<<replace>>'),
 | 
				
			||||||
 | 
					            ('Go to _line', '<<goto-line>>'),
 | 
				
			||||||
 | 
					         ]),
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, editwin):
 | 
				
			||||||
 | 
					        self.editwin = editwin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def find_event(self, event):
 | 
				
			||||||
 | 
					        import SearchDialog
 | 
				
			||||||
 | 
					        SearchDialog.find(self.editwin.text)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def find_again_event(self, event):
 | 
				
			||||||
 | 
					        import SearchDialog
 | 
				
			||||||
 | 
					        SearchDialog.find_again(self.editwin.text)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def find_selection_event(self, event):
 | 
				
			||||||
 | 
					        import SearchDialog
 | 
				
			||||||
 | 
					        SearchDialog.find_selection(self.editwin.text)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def find_in_files_event(self, event):
 | 
				
			||||||
 | 
					        import GrepDialog
 | 
				
			||||||
 | 
					        GrepDialog.grep(self.editwin.text, self.editwin.io, self.editwin.flist)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def replace_event(self, event):
 | 
				
			||||||
 | 
					        import ReplaceDialog
 | 
				
			||||||
 | 
					        ReplaceDialog.replace(self.editwin.text)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def goto_line_event(self, event):
 | 
				
			||||||
 | 
					        text = self.editwin.text
 | 
				
			||||||
 | 
					        lineno = tkSimpleDialog.askinteger("Goto",
 | 
				
			||||||
 | 
					                                           "Go to line number:",
 | 
				
			||||||
 | 
					                                           parent=text)
 | 
				
			||||||
 | 
					        if lineno is None:
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					        if lineno <= 0:
 | 
				
			||||||
 | 
					            text.bell()
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					        text.mark_set("insert", "%d.0" % lineno)
 | 
				
			||||||
 | 
					        text.see("insert")
 | 
				
			||||||
							
								
								
									
										67
									
								
								Lib/idlelib/SearchDialog.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										67
									
								
								Lib/idlelib/SearchDialog.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,67 @@
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					import SearchEngine
 | 
				
			||||||
 | 
					from SearchDialogBase import SearchDialogBase
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _setup(text):
 | 
				
			||||||
 | 
					    root = text._root()
 | 
				
			||||||
 | 
					    engine = SearchEngine.get(root)
 | 
				
			||||||
 | 
					    if not hasattr(engine, "_searchdialog"):
 | 
				
			||||||
 | 
					        engine._searchdialog = SearchDialog(root, engine)
 | 
				
			||||||
 | 
					    return engine._searchdialog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def find(text):
 | 
				
			||||||
 | 
					    return _setup(text).open(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def find_again(text):
 | 
				
			||||||
 | 
					    return _setup(text).find_again(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def find_selection(text):
 | 
				
			||||||
 | 
					    return _setup(text).find_selection(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SearchDialog(SearchDialogBase):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_widgets(self):
 | 
				
			||||||
 | 
					        f = SearchDialogBase.create_widgets(self)
 | 
				
			||||||
 | 
					        self.make_button("Find", self.default_command, 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def default_command(self, event=None):
 | 
				
			||||||
 | 
					        if not self.engine.getprog():
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if self.find_again(self.text):
 | 
				
			||||||
 | 
					            self.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def find_again(self, text):
 | 
				
			||||||
 | 
					        if not self.engine.getpat():
 | 
				
			||||||
 | 
					            self.open(text)
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        if not self.engine.getprog():
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        res = self.engine.search_text(text)
 | 
				
			||||||
 | 
					        if res:
 | 
				
			||||||
 | 
					            line, m = res
 | 
				
			||||||
 | 
					            i, j = m.span()
 | 
				
			||||||
 | 
					            first = "%d.%d" % (line, i)
 | 
				
			||||||
 | 
					            last = "%d.%d" % (line, j)
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                selfirst = text.index("sel.first")
 | 
				
			||||||
 | 
					                sellast = text.index("sel.last")
 | 
				
			||||||
 | 
					                if selfirst == first and sellast == last:
 | 
				
			||||||
 | 
					                    text.bell()
 | 
				
			||||||
 | 
					                    return 0
 | 
				
			||||||
 | 
					            except TclError:
 | 
				
			||||||
 | 
					                pass
 | 
				
			||||||
 | 
					            text.tag_remove("sel", "1.0", "end")
 | 
				
			||||||
 | 
					            text.tag_add("sel", first, last)
 | 
				
			||||||
 | 
					            text.mark_set("insert", self.engine.isback() and first or last)
 | 
				
			||||||
 | 
					            text.see("insert")
 | 
				
			||||||
 | 
					            return 1
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            text.bell()
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def find_selection(self, text):
 | 
				
			||||||
 | 
					        pat = text.get("sel.first", "sel.last")
 | 
				
			||||||
 | 
					        if pat:
 | 
				
			||||||
 | 
					            self.engine.setcookedpat(pat)
 | 
				
			||||||
 | 
					        return self.find_again(text)
 | 
				
			||||||
							
								
								
									
										129
									
								
								Lib/idlelib/SearchDialogBase.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								Lib/idlelib/SearchDialogBase.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,129 @@
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SearchDialogBase:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    title = "Search Dialog"
 | 
				
			||||||
 | 
					    icon = "Search"
 | 
				
			||||||
 | 
					    needwrapbutton = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, root, engine):
 | 
				
			||||||
 | 
					        self.root = root
 | 
				
			||||||
 | 
					        self.engine = engine
 | 
				
			||||||
 | 
					        self.top = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def open(self, text):
 | 
				
			||||||
 | 
					        self.text = text
 | 
				
			||||||
 | 
					        if not self.top:
 | 
				
			||||||
 | 
					            self.create_widgets()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.top.deiconify()
 | 
				
			||||||
 | 
					            self.top.tkraise()
 | 
				
			||||||
 | 
					        self.ent.focus_set()
 | 
				
			||||||
 | 
					        self.ent.selection_range(0, "end")
 | 
				
			||||||
 | 
					        self.ent.icursor(0)
 | 
				
			||||||
 | 
					        self.top.grab_set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self, event=None):
 | 
				
			||||||
 | 
					        if self.top:
 | 
				
			||||||
 | 
					            self.top.grab_release()
 | 
				
			||||||
 | 
					            self.top.withdraw()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_widgets(self):
 | 
				
			||||||
 | 
					        top = Toplevel(self.root)
 | 
				
			||||||
 | 
					        top.bind("<Return>", self.default_command)
 | 
				
			||||||
 | 
					        top.bind("<Escape>", self.close)
 | 
				
			||||||
 | 
					        top.protocol("WM_DELETE_WINDOW", self.close)
 | 
				
			||||||
 | 
					        top.wm_title(self.title)
 | 
				
			||||||
 | 
					        top.wm_iconname(self.icon)
 | 
				
			||||||
 | 
					        self.top = top
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.row = 0
 | 
				
			||||||
 | 
					        self.top.grid_columnconfigure(0, weight=0)
 | 
				
			||||||
 | 
					        self.top.grid_columnconfigure(1, weight=100)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        self.create_entries()
 | 
				
			||||||
 | 
					        self.create_option_buttons()
 | 
				
			||||||
 | 
					        self.create_other_buttons()
 | 
				
			||||||
 | 
					        return self.create_command_buttons()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def make_entry(self, label, var):
 | 
				
			||||||
 | 
					        l = Label(self.top, text=label)
 | 
				
			||||||
 | 
					        l.grid(row=self.row, col=0, sticky="w")
 | 
				
			||||||
 | 
					        e = Entry(self.top, textvariable=var, exportselection=0)
 | 
				
			||||||
 | 
					        e.grid(row=self.row, col=1, sticky="we")
 | 
				
			||||||
 | 
					        self.row = self.row + 1
 | 
				
			||||||
 | 
					        return e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def make_frame(self):
 | 
				
			||||||
 | 
					        f = Frame(self.top)
 | 
				
			||||||
 | 
					        f.grid(row=self.row, col=0, columnspan=2, sticky="we")
 | 
				
			||||||
 | 
					        self.row = self.row + 1
 | 
				
			||||||
 | 
					        return f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def make_button(self, label, command, isdef=0, side="left"):
 | 
				
			||||||
 | 
					        b = Button(self.buttonframe,
 | 
				
			||||||
 | 
					                   text=label, command=command,
 | 
				
			||||||
 | 
					                   default=isdef and "active" or "normal")
 | 
				
			||||||
 | 
					        b.pack(side=side)
 | 
				
			||||||
 | 
					        return b
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_entries(self):
 | 
				
			||||||
 | 
					        self.ent = self.make_entry("Find:", self.engine.patvar)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_option_buttons(self):
 | 
				
			||||||
 | 
					        f = self.make_frame()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        btn = Checkbutton(f, anchor="w",
 | 
				
			||||||
 | 
					                variable=self.engine.revar,
 | 
				
			||||||
 | 
					                text="Regular expression")
 | 
				
			||||||
 | 
					        btn.pack(side="left", fill="both")
 | 
				
			||||||
 | 
					        if self.engine.isre():
 | 
				
			||||||
 | 
					            btn.select()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        btn = Checkbutton(f, anchor="w",
 | 
				
			||||||
 | 
					                variable=self.engine.casevar,
 | 
				
			||||||
 | 
					                text="Match case")
 | 
				
			||||||
 | 
					        btn.pack(side="left", fill="both")
 | 
				
			||||||
 | 
					        if self.engine.iscase():
 | 
				
			||||||
 | 
					            btn.select()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        btn = Checkbutton(f, anchor="w",
 | 
				
			||||||
 | 
					                variable=self.engine.wordvar,
 | 
				
			||||||
 | 
					                text="Whole word")
 | 
				
			||||||
 | 
					        btn.pack(side="left", fill="both")
 | 
				
			||||||
 | 
					        if self.engine.isword():
 | 
				
			||||||
 | 
					            btn.select()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if self.needwrapbutton:
 | 
				
			||||||
 | 
					            btn = Checkbutton(f, anchor="w",
 | 
				
			||||||
 | 
					                    variable=self.engine.wrapvar,
 | 
				
			||||||
 | 
					                    text="Wrap around")
 | 
				
			||||||
 | 
					            btn.pack(side="left", fill="both")
 | 
				
			||||||
 | 
					            if self.engine.iswrap():
 | 
				
			||||||
 | 
					                btn.select()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_other_buttons(self):
 | 
				
			||||||
 | 
					        f = self.make_frame()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        lbl = Label(f, text="Direction: ")
 | 
				
			||||||
 | 
					        lbl.pack(side="left")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        btn = Radiobutton(f, anchor="w",
 | 
				
			||||||
 | 
					                variable=self.engine.backvar, value=1,
 | 
				
			||||||
 | 
					                text="Up")
 | 
				
			||||||
 | 
					        btn.pack(side="left", fill="both")
 | 
				
			||||||
 | 
					        if self.engine.isback():
 | 
				
			||||||
 | 
					            btn.select()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        btn = Radiobutton(f, anchor="w",
 | 
				
			||||||
 | 
					                variable=self.engine.backvar, value=0,
 | 
				
			||||||
 | 
					                text="Down")
 | 
				
			||||||
 | 
					        btn.pack(side="left", fill="both")
 | 
				
			||||||
 | 
					        if not self.engine.isback():
 | 
				
			||||||
 | 
					            btn.select()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def create_command_buttons(self):
 | 
				
			||||||
 | 
					        f = self.buttonframe = self.make_frame()
 | 
				
			||||||
 | 
					        b = self.make_button("close", self.close, side="right")
 | 
				
			||||||
 | 
					        b.lower()
 | 
				
			||||||
							
								
								
									
										221
									
								
								Lib/idlelib/SearchEngine.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										221
									
								
								Lib/idlelib/SearchEngine.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,221 @@
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					import tkMessageBox
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get(root):
 | 
				
			||||||
 | 
					    if not hasattr(root, "_searchengine"):
 | 
				
			||||||
 | 
					        root._searchengine = SearchEngine(root)
 | 
				
			||||||
 | 
					        # XXX This will never garbage-collect -- who cares
 | 
				
			||||||
 | 
					    return root._searchengine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SearchEngine:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, root):
 | 
				
			||||||
 | 
					        self.root = root
 | 
				
			||||||
 | 
					        # State shared by search, replace, and grep;
 | 
				
			||||||
 | 
					        # the search dialogs bind these to UI elements.
 | 
				
			||||||
 | 
					        self.patvar = StringVar(root)           # search pattern
 | 
				
			||||||
 | 
					        self.revar = BooleanVar(root)           # regular expression?
 | 
				
			||||||
 | 
					        self.casevar = BooleanVar(root)         # match case?
 | 
				
			||||||
 | 
					        self.wordvar = BooleanVar(root)         # match whole word?
 | 
				
			||||||
 | 
					        self.wrapvar = BooleanVar(root)         # wrap around buffer?
 | 
				
			||||||
 | 
					        self.wrapvar.set(1)                     # (on by default)
 | 
				
			||||||
 | 
					        self.backvar = BooleanVar(root)         # search backwards?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Access methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getpat(self):
 | 
				
			||||||
 | 
					        return self.patvar.get()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setpat(self, pat):
 | 
				
			||||||
 | 
					        self.patvar.set(pat)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def isre(self):
 | 
				
			||||||
 | 
					        return self.revar.get()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def iscase(self):
 | 
				
			||||||
 | 
					        return self.casevar.get()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def isword(self):
 | 
				
			||||||
 | 
					        return self.wordvar.get()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def iswrap(self):
 | 
				
			||||||
 | 
					        return self.wrapvar.get()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def isback(self):
 | 
				
			||||||
 | 
					        return self.backvar.get()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Higher level access methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getcookedpat(self):
 | 
				
			||||||
 | 
					        pat = self.getpat()
 | 
				
			||||||
 | 
					        if not self.isre():
 | 
				
			||||||
 | 
					            pat = re.escape(pat)
 | 
				
			||||||
 | 
					        if self.isword():
 | 
				
			||||||
 | 
					            pat = r"\b%s\b" % pat
 | 
				
			||||||
 | 
					        return pat
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getprog(self):
 | 
				
			||||||
 | 
					        pat = self.getpat()
 | 
				
			||||||
 | 
					        if not pat:
 | 
				
			||||||
 | 
					            self.report_error(pat, "Empty regular expression")
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        pat = self.getcookedpat()
 | 
				
			||||||
 | 
					        flags = 0
 | 
				
			||||||
 | 
					        if not self.iscase():
 | 
				
			||||||
 | 
					            flags = flags | re.IGNORECASE
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            prog = re.compile(pat, flags)
 | 
				
			||||||
 | 
					        except re.error, what:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                msg, col = what
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                msg = str(what)
 | 
				
			||||||
 | 
					                col = -1
 | 
				
			||||||
 | 
					            self.report_error(pat, msg, col)
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					        return prog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def report_error(self, pat, msg, col=-1):
 | 
				
			||||||
 | 
					        # Derived class could overrid this with something fancier
 | 
				
			||||||
 | 
					        msg = "Error: " + str(msg)
 | 
				
			||||||
 | 
					        if pat:
 | 
				
			||||||
 | 
					            msg = msg + "\np\Pattern: " + str(pat)
 | 
				
			||||||
 | 
					        if col >= 0:
 | 
				
			||||||
 | 
					            msg = msg + "\nOffset: " + str(col)
 | 
				
			||||||
 | 
					        tkMessageBox.showerror("Regular expression error",
 | 
				
			||||||
 | 
					                               msg, master=self.root)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setcookedpat(self, pat):
 | 
				
			||||||
 | 
					        if self.isre():
 | 
				
			||||||
 | 
					            pat = re.escape(pat)
 | 
				
			||||||
 | 
					        self.setpat(pat)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def search_text(self, text, prog=None, ok=0):
 | 
				
			||||||
 | 
					        """Search a text widget for the pattern.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        If prog is given, it should be the precompiled pattern.
 | 
				
			||||||
 | 
					        Return a tuple (lineno, matchobj); None if not found.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        This obeys the wrap and direction (back) settings.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        The search starts at the selection (if there is one) or
 | 
				
			||||||
 | 
					        at the insert mark (otherwise).  If the search is forward,
 | 
				
			||||||
 | 
					        it starts at the right of the selection; for a backward
 | 
				
			||||||
 | 
					        search, it starts at the left end.  An empty match exactly
 | 
				
			||||||
 | 
					        at either end of the selection (or at the insert mark if
 | 
				
			||||||
 | 
					        there is no selection) is ignored  unless the ok flag is true
 | 
				
			||||||
 | 
					        -- this is done to guarantee progress.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        If the search is allowed to wrap around, it will return the
 | 
				
			||||||
 | 
					        original selection if (and only if) it is the only match.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        """
 | 
				
			||||||
 | 
					        if not prog:
 | 
				
			||||||
 | 
					            prog = self.getprog()
 | 
				
			||||||
 | 
					            if not prog:
 | 
				
			||||||
 | 
					                return None # Compilation failed -- stop
 | 
				
			||||||
 | 
					        wrap = self.wrapvar.get()
 | 
				
			||||||
 | 
					        first, last = get_selection(text)
 | 
				
			||||||
 | 
					        if self.isback():
 | 
				
			||||||
 | 
					            if ok:
 | 
				
			||||||
 | 
					                start = last
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                start = first
 | 
				
			||||||
 | 
					            line, col = get_line_col(start)
 | 
				
			||||||
 | 
					            res = self.search_backward(text, prog, line, col, wrap, ok)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if ok:
 | 
				
			||||||
 | 
					                start = first
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                start = last
 | 
				
			||||||
 | 
					            line, col = get_line_col(start)
 | 
				
			||||||
 | 
					            res = self.search_forward(text, prog, line, col, wrap, ok)
 | 
				
			||||||
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def search_forward(self, text, prog, line, col, wrap, ok=0):
 | 
				
			||||||
 | 
					        wrapped = 0
 | 
				
			||||||
 | 
					        startline = line
 | 
				
			||||||
 | 
					        chars = text.get("%d.0" % line, "%d.0" % (line+1))
 | 
				
			||||||
 | 
					        while chars:
 | 
				
			||||||
 | 
					            m = prog.search(chars[:-1], col)
 | 
				
			||||||
 | 
					            if m:
 | 
				
			||||||
 | 
					                if ok or m.end() > col:
 | 
				
			||||||
 | 
					                    return line, m
 | 
				
			||||||
 | 
					            line = line + 1
 | 
				
			||||||
 | 
					            if wrapped and line > startline:
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            col = 0
 | 
				
			||||||
 | 
					            ok = 1
 | 
				
			||||||
 | 
					            chars = text.get("%d.0" % line, "%d.0" % (line+1))
 | 
				
			||||||
 | 
					            if not chars and wrap:
 | 
				
			||||||
 | 
					                wrapped = 1
 | 
				
			||||||
 | 
					                wrap = 0
 | 
				
			||||||
 | 
					                line = 1
 | 
				
			||||||
 | 
					                chars = text.get("1.0", "2.0")
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def search_backward(self, text, prog, line, col, wrap, ok=0):
 | 
				
			||||||
 | 
					        wrapped = 0
 | 
				
			||||||
 | 
					        startline = line
 | 
				
			||||||
 | 
					        chars = text.get("%d.0" % line, "%d.0" % (line+1))
 | 
				
			||||||
 | 
					        while 1:
 | 
				
			||||||
 | 
					            m = search_reverse(prog, chars[:-1], col)
 | 
				
			||||||
 | 
					            if m:
 | 
				
			||||||
 | 
					                if ok or m.start() < col:
 | 
				
			||||||
 | 
					                    return line, m
 | 
				
			||||||
 | 
					            line = line - 1
 | 
				
			||||||
 | 
					            if wrapped and line < startline:
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					            ok = 1
 | 
				
			||||||
 | 
					            if line <= 0:
 | 
				
			||||||
 | 
					                if not wrap:
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					                wrapped = 1
 | 
				
			||||||
 | 
					                wrap = 0
 | 
				
			||||||
 | 
					                pos = text.index("end-1c")
 | 
				
			||||||
 | 
					                line, col = map(int, string.split(pos, "."))
 | 
				
			||||||
 | 
					            chars = text.get("%d.0" % line, "%d.0" % (line+1))
 | 
				
			||||||
 | 
					            col = len(chars) - 1
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Helper to search backwards in a string.
 | 
				
			||||||
 | 
					# (Optimized for the case where the pattern isn't found.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def search_reverse(prog, chars, col):
 | 
				
			||||||
 | 
					    m = prog.search(chars)
 | 
				
			||||||
 | 
					    if not m:
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					    found = None
 | 
				
			||||||
 | 
					    i, j = m.span()
 | 
				
			||||||
 | 
					    while i < col and j <= col:
 | 
				
			||||||
 | 
					        found = m
 | 
				
			||||||
 | 
					        if i == j:
 | 
				
			||||||
 | 
					            j = j+1
 | 
				
			||||||
 | 
					        m = prog.search(chars, j)
 | 
				
			||||||
 | 
					        if not m:
 | 
				
			||||||
 | 
					            break
 | 
				
			||||||
 | 
					        i, j = m.span()
 | 
				
			||||||
 | 
					    return found
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Helper to get selection end points, defaulting to insert mark.
 | 
				
			||||||
 | 
					# Return a tuple of indices ("line.col" strings).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_selection(text):
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        first = text.index("sel.first")
 | 
				
			||||||
 | 
					        last = text.index("sel.last")
 | 
				
			||||||
 | 
					    except TclError:
 | 
				
			||||||
 | 
					        first = last = None
 | 
				
			||||||
 | 
					    if not first:
 | 
				
			||||||
 | 
					        first = text.index("insert")
 | 
				
			||||||
 | 
					    if not last:
 | 
				
			||||||
 | 
					        last = first
 | 
				
			||||||
 | 
					    return first, last
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Helper to parse a text index into a (line, col) tuple.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_line_col(index):
 | 
				
			||||||
 | 
					    line, col = map(int, string.split(index, ".")) # Fails on invalid index
 | 
				
			||||||
 | 
					    return line, col
 | 
				
			||||||
							
								
								
									
										92
									
								
								Lib/idlelib/Separator.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								Lib/idlelib/Separator.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,92 @@
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Separator:
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    def __init__(self, master, orient, min=10, thickness=5, bg=None):
 | 
				
			||||||
 | 
					        self.min = max(1, min)
 | 
				
			||||||
 | 
					        self.thickness = max(1, thickness)
 | 
				
			||||||
 | 
					        if orient in ("h", "horizontal"):
 | 
				
			||||||
 | 
					            self.side = "left"
 | 
				
			||||||
 | 
					            self.dim = "width"
 | 
				
			||||||
 | 
					            self.dir = "x"
 | 
				
			||||||
 | 
					            self.cursor = "sb_h_double_arrow"
 | 
				
			||||||
 | 
					    	elif orient in ("v", "vertical"):
 | 
				
			||||||
 | 
					    	    self.side = "top"
 | 
				
			||||||
 | 
					    	    self.dim = "height"
 | 
				
			||||||
 | 
					    	    self.dir = "y"
 | 
				
			||||||
 | 
					            self.cursor = "sb_v_double_arrow"
 | 
				
			||||||
 | 
					    	else:
 | 
				
			||||||
 | 
					    	    raise ValueError, "Separator: orient should be h or v"
 | 
				
			||||||
 | 
					    	self.winfo_dim = "winfo_" + self.dim
 | 
				
			||||||
 | 
					        self.master = master = Frame(master)
 | 
				
			||||||
 | 
					        master.pack(expand=1, fill="both")
 | 
				
			||||||
 | 
					        self.f1 = Frame(master)
 | 
				
			||||||
 | 
					        self.f1.pack(expand=1, fill="both", side=self.side)
 | 
				
			||||||
 | 
					        self.div = Frame(master, cursor=self.cursor)
 | 
				
			||||||
 | 
					        self.div[self.dim] = self.thickness
 | 
				
			||||||
 | 
					        self.div.pack(fill="both", side=self.side)
 | 
				
			||||||
 | 
					        self.f2 = Frame(master)
 | 
				
			||||||
 | 
					        self.f2.pack(expand=1, fill="both", side=self.side)
 | 
				
			||||||
 | 
					        self.div.bind("<ButtonPress-1>", self.divider_press)
 | 
				
			||||||
 | 
					        if bg:
 | 
				
			||||||
 | 
					            ##self.f1["bg"] = bg
 | 
				
			||||||
 | 
					            ##self.f2["bg"] = bg
 | 
				
			||||||
 | 
					            self.div["bg"] = bg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def parts(self):
 | 
				
			||||||
 | 
					        return self.f1, self.f2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def divider_press(self, event):
 | 
				
			||||||
 | 
					        self.press_event = event
 | 
				
			||||||
 | 
					        self.f1.pack_propagate(0)
 | 
				
			||||||
 | 
					        self.f2.pack_propagate(0)
 | 
				
			||||||
 | 
					        for f in self.f1, self.f2:
 | 
				
			||||||
 | 
					            for dim in "width", "height":
 | 
				
			||||||
 | 
					                f[dim] = getattr(f, "winfo_"+dim)()
 | 
				
			||||||
 | 
					        self.div.bind("<Motion>", self.div_motion)
 | 
				
			||||||
 | 
					        self.div.bind("<ButtonRelease-1>", self.div_release)
 | 
				
			||||||
 | 
					        self.div.grab_set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def div_motion(self, event):
 | 
				
			||||||
 | 
					        delta = getattr(event, self.dir) - getattr(self.press_event, self.dir)
 | 
				
			||||||
 | 
					        if delta:
 | 
				
			||||||
 | 
					            dim1 = getattr(self.f1, self.winfo_dim)()
 | 
				
			||||||
 | 
					            dim2 = getattr(self.f2, self.winfo_dim)()
 | 
				
			||||||
 | 
					            delta = max(delta, self.min-dim1)
 | 
				
			||||||
 | 
					            delta = min(delta, dim2-self.min)
 | 
				
			||||||
 | 
					            dim1 = dim1 + delta
 | 
				
			||||||
 | 
					            dim2 = dim2 - delta
 | 
				
			||||||
 | 
					            self.f1[self.dim] = dim1
 | 
				
			||||||
 | 
					            self.f2[self.dim] = dim2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def div_release(self, event):
 | 
				
			||||||
 | 
					        self.div_motion(event)
 | 
				
			||||||
 | 
					        self.div.unbind("<Motion>")
 | 
				
			||||||
 | 
					        self.div.grab_release()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VSeparator(Separator):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, master, min=10, thickness=5, bg=None):
 | 
				
			||||||
 | 
					        Separator.__init__(self, master, "v", min, thickness, bg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class HSeparator(Separator):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, master, min=10, thickness=5, bg=None):
 | 
				
			||||||
 | 
					        Separator.__init__(self, master, "h", min, thickness, bg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    root = Tk()
 | 
				
			||||||
 | 
					    tlist = []
 | 
				
			||||||
 | 
					    outer = HSeparator(root, bg="red")
 | 
				
			||||||
 | 
					    for part in outer.parts():
 | 
				
			||||||
 | 
					        inner = VSeparator(part, bg="blue")
 | 
				
			||||||
 | 
					        for f in inner.parts():
 | 
				
			||||||
 | 
					            t = Text(f, width=40, height=10, borderwidth=0)
 | 
				
			||||||
 | 
					            t.pack(fill="both", expand=1)
 | 
				
			||||||
 | 
					            tlist.append(t)
 | 
				
			||||||
 | 
					    tlist[0].insert("1.0", "Make your own Mondrian!")
 | 
				
			||||||
 | 
					    tlist[1].insert("1.0", "Move the colored dividers...")
 | 
				
			||||||
 | 
					    root.mainloop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										135
									
								
								Lib/idlelib/StackViewer.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										135
									
								
								Lib/idlelib/StackViewer.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,135 @@
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					import linecache
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					from TreeWidget import TreeNode, TreeItem, ScrolledCanvas
 | 
				
			||||||
 | 
					from ObjectBrowser import ObjectTreeItem, make_objecttreeitem
 | 
				
			||||||
 | 
					from OldStackViewer import StackViewer, NamespaceViewer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def StackBrowser(root, flist=None, stack=None):
 | 
				
			||||||
 | 
					    top = Toplevel(root)
 | 
				
			||||||
 | 
					    sc = ScrolledCanvas(top, bg="white", highlightthickness=0)
 | 
				
			||||||
 | 
					    sc.frame.pack(expand=1, fill="both")
 | 
				
			||||||
 | 
					    item = StackTreeItem(flist)
 | 
				
			||||||
 | 
					    node = TreeNode(sc.canvas, None, item)
 | 
				
			||||||
 | 
					    node.expand()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class StackTreeItem(TreeItem):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, flist=None):
 | 
				
			||||||
 | 
					        self.flist = flist
 | 
				
			||||||
 | 
					        self.stack = get_stack()
 | 
				
			||||||
 | 
					        self.text = get_exception()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetText(self):
 | 
				
			||||||
 | 
					        return self.text
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetSubList(self):
 | 
				
			||||||
 | 
					        sublist = []
 | 
				
			||||||
 | 
					        for info in self.stack:
 | 
				
			||||||
 | 
					            item = FrameTreeItem(info, self.flist)
 | 
				
			||||||
 | 
					            sublist.append(item)
 | 
				
			||||||
 | 
					        return sublist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FrameTreeItem(TreeItem):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, info, flist):
 | 
				
			||||||
 | 
					        self.info = info
 | 
				
			||||||
 | 
					        self.flist = flist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetText(self):
 | 
				
			||||||
 | 
					        frame, lineno = self.info
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            modname = frame.f_globals["__name__"]
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            modname = "?"
 | 
				
			||||||
 | 
					        code = frame.f_code
 | 
				
			||||||
 | 
					        filename = code.co_filename
 | 
				
			||||||
 | 
					        funcname = code.co_name
 | 
				
			||||||
 | 
					        sourceline = linecache.getline(filename, lineno)
 | 
				
			||||||
 | 
					        sourceline = string.strip(sourceline)
 | 
				
			||||||
 | 
					        if funcname in ("?", "", None):
 | 
				
			||||||
 | 
					            item = "%s, line %d: %s" % (modname, lineno, sourceline)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            item = "%s.%s(...), line %d: %s" % (modname, funcname,
 | 
				
			||||||
 | 
					                                             lineno, sourceline)
 | 
				
			||||||
 | 
					##        if i == index:
 | 
				
			||||||
 | 
					##            item = "> " + item
 | 
				
			||||||
 | 
					        return item
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetSubList(self):
 | 
				
			||||||
 | 
					        frame, lineno = self.info
 | 
				
			||||||
 | 
					        sublist = []
 | 
				
			||||||
 | 
					        if frame.f_globals is not frame.f_locals:
 | 
				
			||||||
 | 
					            item = VariablesTreeItem("<locals>", frame.f_locals, self.flist)
 | 
				
			||||||
 | 
					            sublist.append(item)
 | 
				
			||||||
 | 
					        item = VariablesTreeItem("<globals>", frame.f_globals, self.flist)
 | 
				
			||||||
 | 
					        sublist.append(item)
 | 
				
			||||||
 | 
					        return sublist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def OnDoubleClick(self):
 | 
				
			||||||
 | 
					        if self.flist:
 | 
				
			||||||
 | 
					            frame, lineno = self.info
 | 
				
			||||||
 | 
					            filename = frame.f_code.co_filename
 | 
				
			||||||
 | 
					            edit = self.flist.open(filename)
 | 
				
			||||||
 | 
					            edit.gotoline(lineno)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class VariablesTreeItem(ObjectTreeItem):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetText(self):
 | 
				
			||||||
 | 
					        return self.labeltext
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetLabelText(self):
 | 
				
			||||||
 | 
					        return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def IsExpandable(self):
 | 
				
			||||||
 | 
					        return len(self.object) > 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def keys(self):
 | 
				
			||||||
 | 
					        return self.object.keys()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetSubList(self):
 | 
				
			||||||
 | 
					        sublist = []
 | 
				
			||||||
 | 
					        for key in self.keys():
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                value = self.object[key]
 | 
				
			||||||
 | 
					            except KeyError:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            def setfunction(value, key=key, object=self.object):
 | 
				
			||||||
 | 
					                object[key] = value
 | 
				
			||||||
 | 
					            item = make_objecttreeitem(key + " =", value, setfunction)
 | 
				
			||||||
 | 
					            sublist.append(item)
 | 
				
			||||||
 | 
					        return sublist
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					def get_stack(t=None, f=None):
 | 
				
			||||||
 | 
					    if t is None:
 | 
				
			||||||
 | 
					        t = sys.last_traceback
 | 
				
			||||||
 | 
					    stack = []
 | 
				
			||||||
 | 
					    if t and t.tb_frame is f:
 | 
				
			||||||
 | 
					        t = t.tb_next
 | 
				
			||||||
 | 
					    while f is not None:
 | 
				
			||||||
 | 
					        stack.append((f, f.f_lineno))
 | 
				
			||||||
 | 
					        if f is self.botframe:
 | 
				
			||||||
 | 
					            break
 | 
				
			||||||
 | 
					        f = f.f_back
 | 
				
			||||||
 | 
					    stack.reverse()
 | 
				
			||||||
 | 
					    while t is not None:
 | 
				
			||||||
 | 
					        stack.append((t.tb_frame, t.tb_lineno))
 | 
				
			||||||
 | 
					        t = t.tb_next
 | 
				
			||||||
 | 
					    return stack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_exception(type=None, value=None):
 | 
				
			||||||
 | 
					    if type is None:
 | 
				
			||||||
 | 
					        type = sys.last_type
 | 
				
			||||||
 | 
					        value = sys.last_value
 | 
				
			||||||
 | 
					    if hasattr(type, "__name__"):
 | 
				
			||||||
 | 
					        type = type.__name__
 | 
				
			||||||
 | 
					    s = str(type)
 | 
				
			||||||
 | 
					    if value is not None:
 | 
				
			||||||
 | 
					        s = s + ": " + str(value)
 | 
				
			||||||
 | 
					    return s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    root = Tk()
 | 
				
			||||||
 | 
					    root.withdraw()
 | 
				
			||||||
 | 
					    StackBrowser(root)
 | 
				
			||||||
							
								
								
									
										205
									
								
								Lib/idlelib/TODO.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										205
									
								
								Lib/idlelib/TODO.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,205 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TO DO:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- improve debugger:
 | 
				
			||||||
 | 
					    - manage breakpoints globally, allow bp deletion, tbreak, cbreak etc.
 | 
				
			||||||
 | 
					    - real object browser
 | 
				
			||||||
 | 
					    - help on how to use it (a simple help button will do wonders)
 | 
				
			||||||
 | 
					    - performance?  (updates of large sets of locals are slow)
 | 
				
			||||||
 | 
					    - better integration of "debug module"
 | 
				
			||||||
 | 
					    - debugger should be global resource (attached to flist, not to shell)
 | 
				
			||||||
 | 
					    - fix the stupid bug where you need to step twice
 | 
				
			||||||
 | 
					    - display class name in stack viewer entries for methods
 | 
				
			||||||
 | 
					    - suppress tracing through IDLE internals (e.g. print)
 | 
				
			||||||
 | 
					    - add a button to suppress through a specific module or class or method
 | 
				
			||||||
 | 
					- insert the initial current directory into sys.path
 | 
				
			||||||
 | 
					- default directory attribute for each window instead of only for windows
 | 
				
			||||||
 | 
					  that have an associated filename
 | 
				
			||||||
 | 
					- command expansion from keywords, module contents, other buffers, etc.
 | 
				
			||||||
 | 
					- "Recent documents" menu item
 | 
				
			||||||
 | 
					- Filter region command
 | 
				
			||||||
 | 
					- Optional horizontal scroll bar
 | 
				
			||||||
 | 
					- more Emacsisms:
 | 
				
			||||||
 | 
					    - ^K should cut to buffer
 | 
				
			||||||
 | 
					    - M-[, M-] to move by paragraphs
 | 
				
			||||||
 | 
					    - incremental search?
 | 
				
			||||||
 | 
					- search should indicate wrap-around in some way
 | 
				
			||||||
 | 
					- restructure state sensitive code to avoid testing flags all the time
 | 
				
			||||||
 | 
					- persistent user state (e.g. window and cursor positions, bindings)
 | 
				
			||||||
 | 
					- make backups when saving
 | 
				
			||||||
 | 
					- check file mtimes at various points
 | 
				
			||||||
 | 
					- Pluggable interface with RCS/CVS/Perforce/Clearcase
 | 
				
			||||||
 | 
					- better help?
 | 
				
			||||||
 | 
					- don't open second class browser on same module (nor second path browser)
 | 
				
			||||||
 | 
					- unify class and path browsers
 | 
				
			||||||
 | 
					- Need to define a standard way whereby one can determine one is running
 | 
				
			||||||
 | 
					  inside IDLE (needed for Tk mainloop, also handy for $PYTHONSTARTUP)
 | 
				
			||||||
 | 
					- Add more utility methods for use by extensions (a la get_selection)
 | 
				
			||||||
 | 
					- Way to run command in totally separate interpreter (fork+os.system?)
 | 
				
			||||||
 | 
					- Way to find definition of fully-qualified name:
 | 
				
			||||||
 | 
					  In other words, select "UserDict.UserDict", hit some magic key and
 | 
				
			||||||
 | 
					  it loads up UserDict.py and finds the first def or class for UserDict.
 | 
				
			||||||
 | 
					- need a way to force colorization on/off
 | 
				
			||||||
 | 
					- need a way to force auto-indent on/off
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Details:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- when there's a selection, left/right arrow should go to either
 | 
				
			||||||
 | 
					  end of the selection
 | 
				
			||||||
 | 
					- ^O (on Unix -- open-line) should honor autoindent
 | 
				
			||||||
 | 
					- after paste, show end of pasted text
 | 
				
			||||||
 | 
					- on Windows, should turn short filename to long filename (not only in argv!)
 | 
				
			||||||
 | 
					  (shouldn't this be done -- or undone -- by ntpath.normpath?)
 | 
				
			||||||
 | 
					- new autoindent after colon even indents when the colon is in a comment!
 | 
				
			||||||
 | 
					- sometimes forward slashes in pathname remain
 | 
				
			||||||
 | 
					- sometimes star in window name remains in Windows menu
 | 
				
			||||||
 | 
					- With unix bindings, ESC by itself is ignored
 | 
				
			||||||
 | 
					- Sometimes for no apparent reason a selection from the cursor to the
 | 
				
			||||||
 | 
					  end of the command buffer appears, which is hard to get rid of
 | 
				
			||||||
 | 
					  because it stays when you are typing!
 | 
				
			||||||
 | 
					- The Line/Col in the status bar can be wrong initially in PyShell
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Structural problems:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- too much knowledge in FileList about EditorWindow (for example)
 | 
				
			||||||
 | 
					- should add some primitives for accessing the selection etc.
 | 
				
			||||||
 | 
					  to repeat cumbersome code over and over
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					======================================================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Jeff Bauer suggests:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Open Module doesn't appear to handle hierarchical packages.
 | 
				
			||||||
 | 
					- Class browser should also allow hierarchical packages.
 | 
				
			||||||
 | 
					- Open and Open Module could benefit from a history,
 | 
				
			||||||
 | 
					  either command line style, or Microsoft recent-file
 | 
				
			||||||
 | 
					  style.
 | 
				
			||||||
 | 
					- Add a Smalltalk-style inspector  (i.e. Tkinspect)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The last suggestion is already a reality, but not yet
 | 
				
			||||||
 | 
					integrated into IDLE.  I use a module called inspector.py,
 | 
				
			||||||
 | 
					that used to be available from python.org(?)  It no longer
 | 
				
			||||||
 | 
					appears to be in the contributed section, and the source
 | 
				
			||||||
 | 
					has no author attribution.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In any case, the code is useful for visually navigating
 | 
				
			||||||
 | 
					an object's attributes, including its container hierarchy.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    >>> from inspector import Tkinspect
 | 
				
			||||||
 | 
					    >>> Tkinspect(None, myObject)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Tkinspect could probably be extended and refined to
 | 
				
			||||||
 | 
					integrate better into IDLE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					======================================================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Comparison to PTUI
 | 
				
			||||||
 | 
					------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					+ PTUI's help is better (HTML!)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					+ PTUI can attach a shell to any module
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					+ PTUI has some more I/O commands:
 | 
				
			||||||
 | 
					  open multiple
 | 
				
			||||||
 | 
					  append
 | 
				
			||||||
 | 
					  examine (what's that?)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					======================================================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Notes after trying to run Grail
 | 
				
			||||||
 | 
					-------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Grail does stuff to sys.path based on sys.argv[0]; you must set
 | 
				
			||||||
 | 
					sys.argv[0] to something decent first (it is normally set to the path of
 | 
				
			||||||
 | 
					the idle script).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Grail must be exec'ed in __main__ because that's imported by some
 | 
				
			||||||
 | 
					other parts of Grail.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Grail uses a module called History and so does idle :-(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					======================================================================
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Robin Friedrich's items:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Things I'd like to see:
 | 
				
			||||||
 | 
					    - I'd like support for shift-click extending the selection. There's a
 | 
				
			||||||
 | 
					      bug now that it doesn't work the first time you try it.
 | 
				
			||||||
 | 
					    - Printing is needed. How hard can that be on Windows?
 | 
				
			||||||
 | 
					    - The python-mode trick of autoindenting a line with <tab> is neat and
 | 
				
			||||||
 | 
					      very handy.
 | 
				
			||||||
 | 
					    - (someday) a spellchecker for docstrings and comments.
 | 
				
			||||||
 | 
					    - a pagedown/up command key which moves to next class/def statement (top
 | 
				
			||||||
 | 
					      level)
 | 
				
			||||||
 | 
					    - split window capability
 | 
				
			||||||
 | 
					    - DnD text relocation/copying
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Things I don't want to see.
 | 
				
			||||||
 | 
					    - line numbers...  will probably slow things down way too much.
 | 
				
			||||||
 | 
					    - Please use another icon for the tree browser leaf. The small snake
 | 
				
			||||||
 | 
					      isn't cutting it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					----------------------------------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Customizable views (multi-window or multi-pane).  (Markus Gritsch)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Being able to double click (maybe double right click) on a callable
 | 
				
			||||||
 | 
					object in the editor which shows the source of the object, if
 | 
				
			||||||
 | 
					possible.  (Gerrit Holl)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Hooks into the guts, like in Emacs.  (Mike Romberg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Sharing the editor with a remote tutor.  (Martijn Faassen)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Multiple views on the same file.  (Tony J Ibbs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Store breakpoints in a global (per-project) database (GvR); Dirk
 | 
				
			||||||
 | 
					Heise adds: save some space-trimmed context and search around when
 | 
				
			||||||
 | 
					reopening a file that might have been edited by someone else.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Capture menu events in extensions without changing the IDLE source.
 | 
				
			||||||
 | 
					(Matthias Barmeier)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Use overlapping panels (a "notebook" in MFC terms I think) for info
 | 
				
			||||||
 | 
					that doesn't need to be accessible simultaneously (e.g. HTML source
 | 
				
			||||||
 | 
					and output).  Use multi-pane windows for info that does need to be
 | 
				
			||||||
 | 
					shown together (e.g. class browser and source).  (Albert Brandl)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- A project should invisibly track all symbols, for instant search,
 | 
				
			||||||
 | 
					replace and cross-ref.  Projects should be allowed to span multiple
 | 
				
			||||||
 | 
					directories, hosts, etc.  Project management files are placed in a
 | 
				
			||||||
 | 
					directory you specify.  A global mapping between project names and
 | 
				
			||||||
 | 
					project directories should exist [not so sure --GvR].  (Tim Peters)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Merge attr-tips and auto-expand.  (Mark Hammond, Tim Peters)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Python Shell should behave more like a "shell window" as users know
 | 
				
			||||||
 | 
					it -- i.e. you can only edit the current command, and the cursor can't
 | 
				
			||||||
 | 
					escape from the command area.  (Albert Brandl)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Set X11 class to "idle/Idle", set icon and title to something
 | 
				
			||||||
 | 
					beginning with "idle" -- for window manangers.  (Randall Hopper)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Config files editable through a preferences dialog.  (me)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Config files still editable outside the preferences dialog.
 | 
				
			||||||
 | 
					(Randall Hopper)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- When you're editing a command in PyShell, and there are only blank
 | 
				
			||||||
 | 
					lines below the cursor, hitting Return should ignore or delete those
 | 
				
			||||||
 | 
					blank lines rather than deciding you're not on the last line.  (me)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Run command (F5 c.s.) should be more like Pythonwin's Run -- a
 | 
				
			||||||
 | 
					dialog with options to give command line arguments, run the debugger,
 | 
				
			||||||
 | 
					etc.  (me)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Shouldn't be able to delete part of the prompt (or any text before
 | 
				
			||||||
 | 
					it) in the PyShell.  (Martijn Faassen)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Emacs style auto-fill (also smart about comments and strings).
 | 
				
			||||||
 | 
					(Jeremy Hylton)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Output of Run Script should go to a separate output window, not to
 | 
				
			||||||
 | 
					the shell window.  Output of separate runs should all go to the same
 | 
				
			||||||
 | 
					window but clearly delimited.  (David Scherer)
 | 
				
			||||||
							
								
								
									
										87
									
								
								Lib/idlelib/ToolTip.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								Lib/idlelib/ToolTip.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,87 @@
 | 
				
			||||||
 | 
					# Ideas gleaned from PySol
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ToolTipBase:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, button):
 | 
				
			||||||
 | 
					        self.button = button
 | 
				
			||||||
 | 
					        self.tipwindow = None
 | 
				
			||||||
 | 
					        self.id = None
 | 
				
			||||||
 | 
					        self.x = self.y = 0
 | 
				
			||||||
 | 
					        self._id1 = self.button.bind("<Enter>", self.enter)
 | 
				
			||||||
 | 
					        self._id2 = self.button.bind("<Leave>", self.leave)
 | 
				
			||||||
 | 
					        self._id3 = self.button.bind("<ButtonPress>", self.leave)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def enter(self, event=None):
 | 
				
			||||||
 | 
					        self.schedule()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def leave(self, event=None):
 | 
				
			||||||
 | 
					        self.unschedule()
 | 
				
			||||||
 | 
					        self.hidetip()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def schedule(self):
 | 
				
			||||||
 | 
					        self.unschedule()
 | 
				
			||||||
 | 
					        self.id = self.button.after(1500, self.showtip)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def unschedule(self):
 | 
				
			||||||
 | 
					        id = self.id
 | 
				
			||||||
 | 
					        self.id = None
 | 
				
			||||||
 | 
					        if id:
 | 
				
			||||||
 | 
					            self.button.after_cancel(id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def showtip(self):
 | 
				
			||||||
 | 
					        if self.tipwindow:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        # The tip window must be completely outside the button;
 | 
				
			||||||
 | 
					        # otherwise when the mouse enters the tip window we get
 | 
				
			||||||
 | 
					        # a leave event and it disappears, and then we get an enter
 | 
				
			||||||
 | 
					        # event and it reappears, and so on forever :-(
 | 
				
			||||||
 | 
					        x = self.button.winfo_rootx() + 20
 | 
				
			||||||
 | 
					        y = self.button.winfo_rooty() + self.button.winfo_height() + 1
 | 
				
			||||||
 | 
					        self.tipwindow = tw = Toplevel(self.button)
 | 
				
			||||||
 | 
					        tw.wm_overrideredirect(1)
 | 
				
			||||||
 | 
					        tw.wm_geometry("+%d+%d" % (x, y))
 | 
				
			||||||
 | 
					        self.showcontents()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def showcontents(self, text="Your text here"):
 | 
				
			||||||
 | 
					        # Override this in derived class
 | 
				
			||||||
 | 
					        label = Label(self.tipwindow, text=text, justify=LEFT,
 | 
				
			||||||
 | 
					                      background="#ffffe0", relief=SOLID, borderwidth=1)
 | 
				
			||||||
 | 
					        label.pack()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def hidetip(self):
 | 
				
			||||||
 | 
					        tw = self.tipwindow
 | 
				
			||||||
 | 
					        self.tipwindow = None
 | 
				
			||||||
 | 
					        if tw:
 | 
				
			||||||
 | 
					            tw.destroy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ToolTip(ToolTipBase):
 | 
				
			||||||
 | 
					    def __init__(self, button, text):
 | 
				
			||||||
 | 
					        ToolTipBase.__init__(self, button)
 | 
				
			||||||
 | 
					        self.text = text
 | 
				
			||||||
 | 
					    def showcontents(self):
 | 
				
			||||||
 | 
					        ToolTipBase.showcontents(self, self.text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ListboxToolTip(ToolTipBase):
 | 
				
			||||||
 | 
					    def __init__(self, button, items):
 | 
				
			||||||
 | 
					        ToolTipBase.__init__(self, button)
 | 
				
			||||||
 | 
					        self.items = items
 | 
				
			||||||
 | 
					    def showcontents(self):
 | 
				
			||||||
 | 
					        listbox = Listbox(self.tipwindow, background="#ffffe0")
 | 
				
			||||||
 | 
					        listbox.pack()
 | 
				
			||||||
 | 
					        for item in self.items:
 | 
				
			||||||
 | 
					            listbox.insert(END, item)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    # Test code
 | 
				
			||||||
 | 
					    root = Tk()
 | 
				
			||||||
 | 
					    b = Button(root, text="Hello", command=root.destroy)
 | 
				
			||||||
 | 
					    b.pack()
 | 
				
			||||||
 | 
					    root.update()
 | 
				
			||||||
 | 
					    tip = ListboxToolTip(b, ["Hello", "world"])
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    # root.mainloop() # not in idle
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					main()
 | 
				
			||||||
							
								
								
									
										471
									
								
								Lib/idlelib/TreeWidget.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										471
									
								
								Lib/idlelib/TreeWidget.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,471 @@
 | 
				
			||||||
 | 
					# XXX TO DO:
 | 
				
			||||||
 | 
					# - popup menu
 | 
				
			||||||
 | 
					# - support partial or total redisplay
 | 
				
			||||||
 | 
					# - key bindings (instead of quick-n-dirty bindings on Canvas):
 | 
				
			||||||
 | 
					#   - up/down arrow keys to move focus around
 | 
				
			||||||
 | 
					#   - ditto for page up/down, home/end
 | 
				
			||||||
 | 
					#   - left/right arrows to expand/collapse & move out/in
 | 
				
			||||||
 | 
					# - more doc strings
 | 
				
			||||||
 | 
					# - add icons for "file", "module", "class", "method"; better "python" icon
 | 
				
			||||||
 | 
					# - callback for selection???
 | 
				
			||||||
 | 
					# - multiple-item selection
 | 
				
			||||||
 | 
					# - tooltips
 | 
				
			||||||
 | 
					# - redo geometry without magic numbers
 | 
				
			||||||
 | 
					# - keep track of object ids to allow more careful cleaning
 | 
				
			||||||
 | 
					# - optimize tree redraw after expand of subnode
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					import imp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import ZoomHeight
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ICONDIR = "Icons"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Look for Icons subdirectory in the same directory as this module
 | 
				
			||||||
 | 
					try:
 | 
				
			||||||
 | 
					    _icondir = os.path.join(os.path.dirname(__file__), ICONDIR)
 | 
				
			||||||
 | 
					except NameError:
 | 
				
			||||||
 | 
					    _icondir = ICONDIR
 | 
				
			||||||
 | 
					if os.path.isdir(_icondir):
 | 
				
			||||||
 | 
					    ICONDIR = _icondir
 | 
				
			||||||
 | 
					elif not os.path.isdir(ICONDIR):
 | 
				
			||||||
 | 
					    raise RuntimeError, "can't find icon directory (%s)" % `ICONDIR`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def listicons(icondir=ICONDIR):
 | 
				
			||||||
 | 
					    """Utility to display the available icons."""
 | 
				
			||||||
 | 
					    root = Tk()
 | 
				
			||||||
 | 
					    import glob
 | 
				
			||||||
 | 
					    list = glob.glob(os.path.join(icondir, "*.gif"))
 | 
				
			||||||
 | 
					    list.sort()
 | 
				
			||||||
 | 
					    images = []
 | 
				
			||||||
 | 
					    row = column = 0
 | 
				
			||||||
 | 
					    for file in list:
 | 
				
			||||||
 | 
					        name = os.path.splitext(os.path.basename(file))[0]
 | 
				
			||||||
 | 
					        image = PhotoImage(file=file, master=root)
 | 
				
			||||||
 | 
					        images.append(image)
 | 
				
			||||||
 | 
					        label = Label(root, image=image, bd=1, relief="raised")
 | 
				
			||||||
 | 
					        label.grid(row=row, column=column)
 | 
				
			||||||
 | 
					        label = Label(root, text=name)
 | 
				
			||||||
 | 
					        label.grid(row=row+1, column=column)
 | 
				
			||||||
 | 
					        column = column + 1
 | 
				
			||||||
 | 
					        if column >= 10:
 | 
				
			||||||
 | 
					            row = row+2
 | 
				
			||||||
 | 
					            column = 0
 | 
				
			||||||
 | 
					    root.images = images
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TreeNode:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, canvas, parent, item):
 | 
				
			||||||
 | 
					        self.canvas = canvas
 | 
				
			||||||
 | 
					        self.parent = parent
 | 
				
			||||||
 | 
					        self.item = item
 | 
				
			||||||
 | 
					        self.state = 'collapsed'
 | 
				
			||||||
 | 
					        self.selected = 0
 | 
				
			||||||
 | 
					        self.children = []
 | 
				
			||||||
 | 
					        self.x = self.y = None
 | 
				
			||||||
 | 
					        self.iconimages = {} # cache of PhotoImage instances for icons
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def destroy(self):
 | 
				
			||||||
 | 
					        for c in self.children[:]:
 | 
				
			||||||
 | 
					            self.children.remove(c)
 | 
				
			||||||
 | 
					            c.destroy()
 | 
				
			||||||
 | 
					        self.parent = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def geticonimage(self, name):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            return self.iconimages[name]
 | 
				
			||||||
 | 
					        except KeyError:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        file, ext = os.path.splitext(name)
 | 
				
			||||||
 | 
					        ext = ext or ".gif"
 | 
				
			||||||
 | 
					        fullname = os.path.join(ICONDIR, file + ext)
 | 
				
			||||||
 | 
					        image = PhotoImage(master=self.canvas, file=fullname)
 | 
				
			||||||
 | 
					        self.iconimages[name] = image
 | 
				
			||||||
 | 
					        return image
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def select(self, event=None):
 | 
				
			||||||
 | 
					        if self.selected:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.deselectall()
 | 
				
			||||||
 | 
					        self.selected = 1
 | 
				
			||||||
 | 
					        self.canvas.delete(self.image_id)
 | 
				
			||||||
 | 
					        self.drawicon()
 | 
				
			||||||
 | 
					        self.drawtext()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def deselect(self, event=None):
 | 
				
			||||||
 | 
					        if not self.selected:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        self.selected = 0
 | 
				
			||||||
 | 
					        self.canvas.delete(self.image_id)
 | 
				
			||||||
 | 
					        self.drawicon()
 | 
				
			||||||
 | 
					        self.drawtext()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def deselectall(self):
 | 
				
			||||||
 | 
					        if self.parent:
 | 
				
			||||||
 | 
					            self.parent.deselectall()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.deselecttree()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def deselecttree(self):
 | 
				
			||||||
 | 
					        if self.selected:
 | 
				
			||||||
 | 
					            self.deselect()
 | 
				
			||||||
 | 
					        for child in self.children:
 | 
				
			||||||
 | 
					            child.deselecttree()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def flip(self, event=None):
 | 
				
			||||||
 | 
					        if self.state == 'expanded':
 | 
				
			||||||
 | 
					            self.collapse()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.expand()
 | 
				
			||||||
 | 
					        self.item.OnDoubleClick()
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def expand(self, event=None):
 | 
				
			||||||
 | 
					        if not self.item._IsExpandable():
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if self.state != 'expanded':
 | 
				
			||||||
 | 
					            self.state = 'expanded'
 | 
				
			||||||
 | 
					            self.update()
 | 
				
			||||||
 | 
					            self.view()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def collapse(self, event=None):
 | 
				
			||||||
 | 
					        if self.state != 'collapsed':
 | 
				
			||||||
 | 
					            self.state = 'collapsed'
 | 
				
			||||||
 | 
					            self.update()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def view(self):
 | 
				
			||||||
 | 
					        top = self.y - 2
 | 
				
			||||||
 | 
					        bottom = self.lastvisiblechild().y + 17
 | 
				
			||||||
 | 
					        height = bottom - top
 | 
				
			||||||
 | 
					        visible_top = self.canvas.canvasy(0)
 | 
				
			||||||
 | 
					        visible_height = self.canvas.winfo_height()
 | 
				
			||||||
 | 
					        visible_bottom = self.canvas.canvasy(visible_height)
 | 
				
			||||||
 | 
					        if visible_top <= top and bottom <= visible_bottom:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        x0, y0, x1, y1 = self.canvas._getints(self.canvas['scrollregion'])
 | 
				
			||||||
 | 
					        if top >= visible_top and height <= visible_height:
 | 
				
			||||||
 | 
					            fraction = top + height - visible_height
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            fraction = top
 | 
				
			||||||
 | 
					        fraction = float(fraction) / y1
 | 
				
			||||||
 | 
					        self.canvas.yview_moveto(fraction)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def lastvisiblechild(self):
 | 
				
			||||||
 | 
					        if self.children and self.state == 'expanded':
 | 
				
			||||||
 | 
					            return self.children[-1].lastvisiblechild()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return self
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def update(self):
 | 
				
			||||||
 | 
					        if self.parent:
 | 
				
			||||||
 | 
					            self.parent.update()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            oldcursor = self.canvas['cursor']
 | 
				
			||||||
 | 
					            self.canvas['cursor'] = "watch"
 | 
				
			||||||
 | 
					            self.canvas.update()
 | 
				
			||||||
 | 
					            self.canvas.delete(ALL)     # XXX could be more subtle
 | 
				
			||||||
 | 
					            self.draw(7, 2)
 | 
				
			||||||
 | 
					            x0, y0, x1, y1 = self.canvas.bbox(ALL)
 | 
				
			||||||
 | 
					            self.canvas.configure(scrollregion=(0, 0, x1, y1))
 | 
				
			||||||
 | 
					            self.canvas['cursor'] = oldcursor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def draw(self, x, y):
 | 
				
			||||||
 | 
					        # XXX This hard-codes too many geometry constants!
 | 
				
			||||||
 | 
					        self.x, self.y = x, y
 | 
				
			||||||
 | 
					        self.drawicon()
 | 
				
			||||||
 | 
					        self.drawtext()
 | 
				
			||||||
 | 
					        if self.state != 'expanded':
 | 
				
			||||||
 | 
					            return y+17
 | 
				
			||||||
 | 
					        # draw children
 | 
				
			||||||
 | 
					        if not self.children:
 | 
				
			||||||
 | 
					            sublist = self.item._GetSubList()
 | 
				
			||||||
 | 
					            if not sublist:
 | 
				
			||||||
 | 
					                # _IsExpandable() was mistaken; that's allowed
 | 
				
			||||||
 | 
					                return y+17
 | 
				
			||||||
 | 
					            for item in sublist:
 | 
				
			||||||
 | 
					                child = TreeNode(self.canvas, self, item)
 | 
				
			||||||
 | 
					                self.children.append(child)
 | 
				
			||||||
 | 
					        cx = x+20
 | 
				
			||||||
 | 
					        cy = y+17
 | 
				
			||||||
 | 
					        cylast = 0
 | 
				
			||||||
 | 
					        for child in self.children:
 | 
				
			||||||
 | 
					            cylast = cy
 | 
				
			||||||
 | 
					            self.canvas.create_line(x+9, cy+7, cx, cy+7, fill="gray50")
 | 
				
			||||||
 | 
					            cy = child.draw(cx, cy)
 | 
				
			||||||
 | 
					            if child.item._IsExpandable():
 | 
				
			||||||
 | 
					                if child.state == 'expanded':
 | 
				
			||||||
 | 
					                    iconname = "minusnode"
 | 
				
			||||||
 | 
					                    callback = child.collapse
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    iconname = "plusnode"
 | 
				
			||||||
 | 
					                    callback = child.expand
 | 
				
			||||||
 | 
					                image = self.geticonimage(iconname)
 | 
				
			||||||
 | 
					                id = self.canvas.create_image(x+9, cylast+7, image=image)
 | 
				
			||||||
 | 
					                # XXX This leaks bindings until canvas is deleted:
 | 
				
			||||||
 | 
					                self.canvas.tag_bind(id, "<1>", callback)
 | 
				
			||||||
 | 
					                self.canvas.tag_bind(id, "<Double-1>", lambda x: None)
 | 
				
			||||||
 | 
					        id = self.canvas.create_line(x+9, y+10, x+9, cylast+7,
 | 
				
			||||||
 | 
					            ##stipple="gray50",     # XXX Seems broken in Tk 8.0.x
 | 
				
			||||||
 | 
					            fill="gray50")
 | 
				
			||||||
 | 
					        self.canvas.tag_lower(id) # XXX .lower(id) before Python 1.5.2
 | 
				
			||||||
 | 
					        return cy
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def drawicon(self):
 | 
				
			||||||
 | 
					        if self.selected:
 | 
				
			||||||
 | 
					            imagename = (self.item.GetSelectedIconName() or
 | 
				
			||||||
 | 
					                         self.item.GetIconName() or
 | 
				
			||||||
 | 
					                         "openfolder")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            imagename = self.item.GetIconName() or "folder"
 | 
				
			||||||
 | 
					        image = self.geticonimage(imagename)
 | 
				
			||||||
 | 
					        id = self.canvas.create_image(self.x, self.y, anchor="nw", image=image)
 | 
				
			||||||
 | 
					        self.image_id = id
 | 
				
			||||||
 | 
					        self.canvas.tag_bind(id, "<1>", self.select)
 | 
				
			||||||
 | 
					        self.canvas.tag_bind(id, "<Double-1>", self.flip)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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)
 | 
				
			||||||
 | 
					        if self.selected:
 | 
				
			||||||
 | 
					            self.label.configure(fg="white", bg="darkblue")
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.label.configure(fg="black", bg="white")
 | 
				
			||||||
 | 
					        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 select_or_edit(self, event=None):
 | 
				
			||||||
 | 
					        if self.selected and self.item.IsEditable():
 | 
				
			||||||
 | 
					            self.edit(event)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.select(event)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def edit(self, event=None):
 | 
				
			||||||
 | 
					        self.entry = Entry(self.label, bd=0, highlightthickness=1, width=0)
 | 
				
			||||||
 | 
					        self.entry.insert(0, self.label['text'])
 | 
				
			||||||
 | 
					        self.entry.selection_range(0, END)
 | 
				
			||||||
 | 
					        self.entry.pack(ipadx=5)
 | 
				
			||||||
 | 
					        self.entry.focus_set()
 | 
				
			||||||
 | 
					        self.entry.bind("<Return>", self.edit_finish)
 | 
				
			||||||
 | 
					        self.entry.bind("<Escape>", self.edit_cancel)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def edit_finish(self, event=None):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            entry = self.entry
 | 
				
			||||||
 | 
					            del self.entry
 | 
				
			||||||
 | 
					        except AttributeError:
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        text = entry.get()
 | 
				
			||||||
 | 
					        entry.destroy()
 | 
				
			||||||
 | 
					        if text and text != self.item.GetText():
 | 
				
			||||||
 | 
					            self.item.SetText(text)
 | 
				
			||||||
 | 
					        text = self.item.GetText()
 | 
				
			||||||
 | 
					        self.label['text'] = text
 | 
				
			||||||
 | 
					        self.drawtext()
 | 
				
			||||||
 | 
					        self.canvas.focus_set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def edit_cancel(self, event=None):
 | 
				
			||||||
 | 
					        self.drawtext()
 | 
				
			||||||
 | 
					        self.canvas.focus_set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class TreeItem:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """Abstract class representing tree items.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Methods should typically be overridden, otherwise a default action
 | 
				
			||||||
 | 
					    is used.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        """Constructor.  Do whatever you need to do."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetText(self):
 | 
				
			||||||
 | 
					        """Return text string to display."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetLabelText(self):
 | 
				
			||||||
 | 
					        """Return label text string to display in front of text (if any)."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    expandable = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _IsExpandable(self):
 | 
				
			||||||
 | 
					        """Do not override!  Called by TreeNode."""
 | 
				
			||||||
 | 
					        if self.expandable is None:
 | 
				
			||||||
 | 
					            self.expandable = self.IsExpandable()
 | 
				
			||||||
 | 
					        return self.expandable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def IsExpandable(self):
 | 
				
			||||||
 | 
					        """Return whether there are subitems."""
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _GetSubList(self):
 | 
				
			||||||
 | 
					        """Do not override!  Called by TreeNode."""
 | 
				
			||||||
 | 
					        if not self.IsExpandable():
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					        sublist = self.GetSubList()
 | 
				
			||||||
 | 
					        if not sublist:
 | 
				
			||||||
 | 
					            self.expandable = 0
 | 
				
			||||||
 | 
					        return sublist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def IsEditable(self):
 | 
				
			||||||
 | 
					        """Return whether the item's text may be edited."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def SetText(self, text):
 | 
				
			||||||
 | 
					        """Change the item's text (if it is editable)."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetIconName(self):
 | 
				
			||||||
 | 
					        """Return name of icon to be displayed normally."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetSelectedIconName(self):
 | 
				
			||||||
 | 
					        """Return name of icon to be displayed when selected."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetSubList(self):
 | 
				
			||||||
 | 
					        """Return list of items forming sublist."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def OnDoubleClick(self):
 | 
				
			||||||
 | 
					        """Called on a double-click on the item."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Example application
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class FileTreeItem(TreeItem):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """Example TreeItem subclass -- browse the file system."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, path):
 | 
				
			||||||
 | 
					        self.path = path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetText(self):
 | 
				
			||||||
 | 
					        return os.path.basename(self.path) or self.path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def IsEditable(self):
 | 
				
			||||||
 | 
					        return os.path.basename(self.path) != ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def SetText(self, text):
 | 
				
			||||||
 | 
					        newpath = os.path.dirname(self.path)
 | 
				
			||||||
 | 
					        newpath = os.path.join(newpath, text)
 | 
				
			||||||
 | 
					        if os.path.dirname(newpath) != os.path.dirname(self.path):
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            os.rename(self.path, newpath)
 | 
				
			||||||
 | 
					            self.path = newpath
 | 
				
			||||||
 | 
					        except os.error:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetIconName(self):
 | 
				
			||||||
 | 
					        if not self.IsExpandable():
 | 
				
			||||||
 | 
					            return "python" # XXX wish there was a "file" icon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def IsExpandable(self):
 | 
				
			||||||
 | 
					        return os.path.isdir(self.path)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def GetSubList(self):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            names = os.listdir(self.path)
 | 
				
			||||||
 | 
					        except os.error:
 | 
				
			||||||
 | 
					            return []
 | 
				
			||||||
 | 
					        names.sort(lambda a, b: cmp(os.path.normcase(a), os.path.normcase(b)))
 | 
				
			||||||
 | 
					        sublist = []
 | 
				
			||||||
 | 
					        for name in names:
 | 
				
			||||||
 | 
					            item = FileTreeItem(os.path.join(self.path, name))
 | 
				
			||||||
 | 
					            sublist.append(item)
 | 
				
			||||||
 | 
					        return sublist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# A canvas widget with scroll bars and some useful bindings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ScrolledCanvas:
 | 
				
			||||||
 | 
					    def __init__(self, master, **opts):
 | 
				
			||||||
 | 
					        if not opts.has_key('yscrollincrement'):
 | 
				
			||||||
 | 
					            opts['yscrollincrement'] = 17
 | 
				
			||||||
 | 
					        self.master = master
 | 
				
			||||||
 | 
					        self.frame = Frame(master)
 | 
				
			||||||
 | 
					        self.frame.rowconfigure(0, weight=1)
 | 
				
			||||||
 | 
					        self.frame.columnconfigure(0, weight=1)
 | 
				
			||||||
 | 
					        self.canvas = apply(Canvas, (self.frame,), opts)
 | 
				
			||||||
 | 
					        self.canvas.grid(row=0, column=0, sticky="nsew")
 | 
				
			||||||
 | 
					        self.vbar = Scrollbar(self.frame, name="vbar")
 | 
				
			||||||
 | 
					        self.vbar.grid(row=0, column=1, sticky="nse")
 | 
				
			||||||
 | 
					        self.hbar = Scrollbar(self.frame, name="hbar", orient="horizontal")
 | 
				
			||||||
 | 
					        self.hbar.grid(row=1, column=0, sticky="ews")
 | 
				
			||||||
 | 
					        self.canvas['yscrollcommand'] = self.vbar.set
 | 
				
			||||||
 | 
					        self.vbar['command'] = self.canvas.yview
 | 
				
			||||||
 | 
					        self.canvas['xscrollcommand'] = self.hbar.set
 | 
				
			||||||
 | 
					        self.hbar['command'] = self.canvas.xview
 | 
				
			||||||
 | 
					        self.canvas.bind("<Key-Prior>", self.page_up)
 | 
				
			||||||
 | 
					        self.canvas.bind("<Key-Next>", self.page_down)
 | 
				
			||||||
 | 
					        self.canvas.bind("<Key-Up>", self.unit_up)
 | 
				
			||||||
 | 
					        self.canvas.bind("<Key-Down>", self.unit_down)
 | 
				
			||||||
 | 
					        if isinstance(master, Toplevel) or isinstance(master, Tk):
 | 
				
			||||||
 | 
					            self.canvas.bind("<Alt-F2>", self.zoom_height)
 | 
				
			||||||
 | 
					        self.canvas.focus_set()
 | 
				
			||||||
 | 
					    def page_up(self, event):
 | 
				
			||||||
 | 
					        self.canvas.yview_scroll(-1, "page")
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					    def page_down(self, event):
 | 
				
			||||||
 | 
					        self.canvas.yview_scroll(1, "page")
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					    def unit_up(self, event):
 | 
				
			||||||
 | 
					        self.canvas.yview_scroll(-1, "unit")
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					    def unit_down(self, event):
 | 
				
			||||||
 | 
					        self.canvas.yview_scroll(1, "unit")
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					    def zoom_height(self, event):
 | 
				
			||||||
 | 
					        ZoomHeight.zoom_height(self.master)
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Testing functions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test():
 | 
				
			||||||
 | 
					    import PyShell
 | 
				
			||||||
 | 
					    root = Toplevel(PyShell.root)
 | 
				
			||||||
 | 
					    root.configure(bd=0, bg="yellow")
 | 
				
			||||||
 | 
					    root.focus_set()
 | 
				
			||||||
 | 
					    sc = ScrolledCanvas(root, bg="white", highlightthickness=0, takefocus=1)
 | 
				
			||||||
 | 
					    sc.frame.pack(expand=1, fill="both")
 | 
				
			||||||
 | 
					    item = FileTreeItem("C:/windows/desktop")
 | 
				
			||||||
 | 
					    node = TreeNode(sc.canvas, None, item)
 | 
				
			||||||
 | 
					    node.expand()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test2():
 | 
				
			||||||
 | 
					    # test w/o scrolling canvas
 | 
				
			||||||
 | 
					    root = Tk()
 | 
				
			||||||
 | 
					    root.configure(bd=0)
 | 
				
			||||||
 | 
					    canvas = Canvas(root, bg="white", highlightthickness=0)
 | 
				
			||||||
 | 
					    canvas.pack(expand=1, fill="both")
 | 
				
			||||||
 | 
					    item = FileTreeItem(os.curdir)
 | 
				
			||||||
 | 
					    node = TreeNode(canvas, None, item)
 | 
				
			||||||
 | 
					    node.update()
 | 
				
			||||||
 | 
					    canvas.focus_set()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    test()
 | 
				
			||||||
							
								
								
									
										352
									
								
								Lib/idlelib/UndoDelegator.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										352
									
								
								Lib/idlelib/UndoDelegator.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,352 @@
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					from Delegator import Delegator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<redo>>
 | 
				
			||||||
 | 
					#$ win <Control-y>
 | 
				
			||||||
 | 
					#$ unix <Alt-z>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<undo>>
 | 
				
			||||||
 | 
					#$ win <Control-z>
 | 
				
			||||||
 | 
					#$ unix <Control-z>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#$ event <<dump-undo-state>>
 | 
				
			||||||
 | 
					#$ win <Control-backslash>
 | 
				
			||||||
 | 
					#$ unix <Control-backslash>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UndoDelegator(Delegator):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    max_undo = 1000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        Delegator.__init__(self)
 | 
				
			||||||
 | 
					        self.reset_undo()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def setdelegate(self, delegate):
 | 
				
			||||||
 | 
					        if self.delegate is not None:
 | 
				
			||||||
 | 
					            self.unbind("<<undo>>")
 | 
				
			||||||
 | 
					            self.unbind("<<redo>>")
 | 
				
			||||||
 | 
					            self.unbind("<<dump-undo-state>>")
 | 
				
			||||||
 | 
					        Delegator.setdelegate(self, delegate)
 | 
				
			||||||
 | 
					        if delegate is not None:
 | 
				
			||||||
 | 
					            self.bind("<<undo>>", self.undo_event)
 | 
				
			||||||
 | 
					            self.bind("<<redo>>", self.redo_event)
 | 
				
			||||||
 | 
					            self.bind("<<dump-undo-state>>", self.dump_event)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dump_event(self, event):
 | 
				
			||||||
 | 
					        from pprint import pprint
 | 
				
			||||||
 | 
					        pprint(self.undolist[:self.pointer])
 | 
				
			||||||
 | 
					        print "pointer:", self.pointer,
 | 
				
			||||||
 | 
					        print "saved:", self.saved,
 | 
				
			||||||
 | 
					        print "can_merge:", self.can_merge,
 | 
				
			||||||
 | 
					        print "get_saved():", self.get_saved()
 | 
				
			||||||
 | 
					        pprint(self.undolist[self.pointer:])
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def reset_undo(self):
 | 
				
			||||||
 | 
					        self.was_saved = -1
 | 
				
			||||||
 | 
					        self.pointer = 0
 | 
				
			||||||
 | 
					        self.undolist = []
 | 
				
			||||||
 | 
					        self.undoblock = 0  # or a CommandSequence instance
 | 
				
			||||||
 | 
					        self.set_saved(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_saved(self, flag):
 | 
				
			||||||
 | 
					        if flag:
 | 
				
			||||||
 | 
					            self.saved = self.pointer
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.saved = -1
 | 
				
			||||||
 | 
					        self.can_merge = 0
 | 
				
			||||||
 | 
					        self.check_saved()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_saved(self):
 | 
				
			||||||
 | 
					        return self.saved == self.pointer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    saved_change_hook = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_saved_change_hook(self, hook):
 | 
				
			||||||
 | 
					        self.saved_change_hook = hook
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    was_saved = -1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def check_saved(self):
 | 
				
			||||||
 | 
					        is_saved = self.get_saved()
 | 
				
			||||||
 | 
					        if is_saved != self.was_saved:
 | 
				
			||||||
 | 
					            self.was_saved = is_saved
 | 
				
			||||||
 | 
					            if self.saved_change_hook:
 | 
				
			||||||
 | 
					                self.saved_change_hook()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def insert(self, index, chars, tags=None):
 | 
				
			||||||
 | 
					        self.addcmd(InsertCommand(index, chars, tags))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete(self, index1, index2=None):
 | 
				
			||||||
 | 
					        self.addcmd(DeleteCommand(index1, index2))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Clients should call undo_block_start() and undo_block_stop()
 | 
				
			||||||
 | 
					    # around a sequence of editing cmds to be treated as a unit by
 | 
				
			||||||
 | 
					    # undo & redo.  Nested matching calls are OK, and the inner calls
 | 
				
			||||||
 | 
					    # then act like nops.  OK too if no editing cmds, or only one
 | 
				
			||||||
 | 
					    # editing cmd, is issued in between:  if no cmds, the whole
 | 
				
			||||||
 | 
					    # sequence has no effect; and if only one cmd, that cmd is entered
 | 
				
			||||||
 | 
					    # directly into the undo list, as if undo_block_xxx hadn't been
 | 
				
			||||||
 | 
					    # called.  The intent of all that is to make this scheme easy
 | 
				
			||||||
 | 
					    # to use:  all the client has to worry about is making sure each
 | 
				
			||||||
 | 
					    # _start() call is matched by a _stop() call.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def undo_block_start(self):
 | 
				
			||||||
 | 
					        if self.undoblock == 0:
 | 
				
			||||||
 | 
					            self.undoblock = CommandSequence()
 | 
				
			||||||
 | 
					        self.undoblock.bump_depth()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def undo_block_stop(self):
 | 
				
			||||||
 | 
					        if self.undoblock.bump_depth(-1) == 0:
 | 
				
			||||||
 | 
					            cmd = self.undoblock
 | 
				
			||||||
 | 
					            self.undoblock = 0
 | 
				
			||||||
 | 
					            if len(cmd) > 0:
 | 
				
			||||||
 | 
					                if len(cmd) == 1:
 | 
				
			||||||
 | 
					                    # no need to wrap a single cmd
 | 
				
			||||||
 | 
					                    cmd = cmd.getcmd(0)
 | 
				
			||||||
 | 
					                # this blk of cmds, or single cmd, has already
 | 
				
			||||||
 | 
					                # been done, so don't execute it again
 | 
				
			||||||
 | 
					                self.addcmd(cmd, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def addcmd(self, cmd, execute=1):
 | 
				
			||||||
 | 
					        if execute:
 | 
				
			||||||
 | 
					            cmd.do(self.delegate)
 | 
				
			||||||
 | 
					        if self.undoblock != 0:
 | 
				
			||||||
 | 
					            self.undoblock.append(cmd)
 | 
				
			||||||
 | 
					            return
 | 
				
			||||||
 | 
					        if self.can_merge and self.pointer > 0:
 | 
				
			||||||
 | 
					            lastcmd = self.undolist[self.pointer-1]
 | 
				
			||||||
 | 
					            if lastcmd.merge(cmd):
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					        self.undolist[self.pointer:] = [cmd]
 | 
				
			||||||
 | 
					        if self.saved > self.pointer:
 | 
				
			||||||
 | 
					            self.saved = -1
 | 
				
			||||||
 | 
					        self.pointer = self.pointer + 1
 | 
				
			||||||
 | 
					        if len(self.undolist) > self.max_undo:
 | 
				
			||||||
 | 
					            ##print "truncating undo list"
 | 
				
			||||||
 | 
					            del self.undolist[0]
 | 
				
			||||||
 | 
					            self.pointer = self.pointer - 1
 | 
				
			||||||
 | 
					            if self.saved >= 0:
 | 
				
			||||||
 | 
					                self.saved = self.saved - 1
 | 
				
			||||||
 | 
					        self.can_merge = 1
 | 
				
			||||||
 | 
					        self.check_saved()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def undo_event(self, event):
 | 
				
			||||||
 | 
					        if self.pointer == 0:
 | 
				
			||||||
 | 
					            self.bell()
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					        cmd = self.undolist[self.pointer - 1]
 | 
				
			||||||
 | 
					        cmd.undo(self.delegate)
 | 
				
			||||||
 | 
					        self.pointer = self.pointer - 1
 | 
				
			||||||
 | 
					        self.can_merge = 0
 | 
				
			||||||
 | 
					        self.check_saved()
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def redo_event(self, event):
 | 
				
			||||||
 | 
					        if self.pointer >= len(self.undolist):
 | 
				
			||||||
 | 
					            self.bell()
 | 
				
			||||||
 | 
					            return "break"
 | 
				
			||||||
 | 
					        cmd = self.undolist[self.pointer]
 | 
				
			||||||
 | 
					        cmd.redo(self.delegate)
 | 
				
			||||||
 | 
					        self.pointer = self.pointer + 1
 | 
				
			||||||
 | 
					        self.can_merge = 0
 | 
				
			||||||
 | 
					        self.check_saved()
 | 
				
			||||||
 | 
					        return "break"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Command:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Base class for Undoable commands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    tags = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, index1, index2, chars, tags=None):
 | 
				
			||||||
 | 
					        self.marks_before = {}
 | 
				
			||||||
 | 
					        self.marks_after = {}
 | 
				
			||||||
 | 
					        self.index1 = index1
 | 
				
			||||||
 | 
					        self.index2 = index2
 | 
				
			||||||
 | 
					        self.chars = chars
 | 
				
			||||||
 | 
					        if tags:
 | 
				
			||||||
 | 
					            self.tags = tags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __repr__(self):
 | 
				
			||||||
 | 
					        s = self.__class__.__name__
 | 
				
			||||||
 | 
					        t = (self.index1, self.index2, self.chars, self.tags)
 | 
				
			||||||
 | 
					        if self.tags is None:
 | 
				
			||||||
 | 
					            t = t[:-1]
 | 
				
			||||||
 | 
					        return s + `t`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def do(self, text):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def redo(self, text):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def undo(self, text):
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def merge(self, cmd):
 | 
				
			||||||
 | 
					        return 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def save_marks(self, text):
 | 
				
			||||||
 | 
					        marks = {}
 | 
				
			||||||
 | 
					        for name in text.mark_names():
 | 
				
			||||||
 | 
					            if name != "insert" and name != "current":
 | 
				
			||||||
 | 
					                marks[name] = text.index(name)
 | 
				
			||||||
 | 
					        return marks
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def set_marks(self, text, marks):
 | 
				
			||||||
 | 
					        for name, index in marks.items():
 | 
				
			||||||
 | 
					            text.mark_set(name, index)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class InsertCommand(Command):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Undoable insert command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, index1, chars, tags=None):
 | 
				
			||||||
 | 
					        Command.__init__(self, index1, None, chars, tags)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def do(self, text):
 | 
				
			||||||
 | 
					        self.marks_before = self.save_marks(text)
 | 
				
			||||||
 | 
					        self.index1 = text.index(self.index1)
 | 
				
			||||||
 | 
					        if text.compare(self.index1, ">", "end-1c"):
 | 
				
			||||||
 | 
					            # Insert before the final newline
 | 
				
			||||||
 | 
					            self.index1 = text.index("end-1c")
 | 
				
			||||||
 | 
					        text.insert(self.index1, self.chars, self.tags)
 | 
				
			||||||
 | 
					        self.index2 = text.index("%s+%dc" % (self.index1, len(self.chars)))
 | 
				
			||||||
 | 
					        self.marks_after = self.save_marks(text)
 | 
				
			||||||
 | 
					        ##sys.__stderr__.write("do: %s\n" % self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def redo(self, text):
 | 
				
			||||||
 | 
					        text.mark_set('insert', self.index1)
 | 
				
			||||||
 | 
					        text.insert(self.index1, self.chars, self.tags)
 | 
				
			||||||
 | 
					        self.set_marks(text, self.marks_after)
 | 
				
			||||||
 | 
					        text.see('insert')
 | 
				
			||||||
 | 
					        ##sys.__stderr__.write("redo: %s\n" % self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def undo(self, text):
 | 
				
			||||||
 | 
					        text.mark_set('insert', self.index1)
 | 
				
			||||||
 | 
					        text.delete(self.index1, self.index2)
 | 
				
			||||||
 | 
					        self.set_marks(text, self.marks_before)
 | 
				
			||||||
 | 
					        text.see('insert')
 | 
				
			||||||
 | 
					        ##sys.__stderr__.write("undo: %s\n" % self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def merge(self, cmd):
 | 
				
			||||||
 | 
					        if self.__class__ is not cmd.__class__:
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        if self.index2 != cmd.index1:
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        if self.tags != cmd.tags:
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        if len(cmd.chars) != 1:
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        if self.chars and \
 | 
				
			||||||
 | 
					           self.classify(self.chars[-1]) != self.classify(cmd.chars):
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        self.index2 = cmd.index2
 | 
				
			||||||
 | 
					        self.chars = self.chars + cmd.chars
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    alphanumeric = string.letters + string.digits + "_"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def classify(self, c):
 | 
				
			||||||
 | 
					        if c in self.alphanumeric:
 | 
				
			||||||
 | 
					            return "alphanumeric"
 | 
				
			||||||
 | 
					        if c == "\n":
 | 
				
			||||||
 | 
					            return "newline"
 | 
				
			||||||
 | 
					        return "punctuation"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class DeleteCommand(Command):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Undoable delete command
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, index1, index2=None):
 | 
				
			||||||
 | 
					        Command.__init__(self, index1, index2, None, None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def do(self, text):
 | 
				
			||||||
 | 
					        self.marks_before = self.save_marks(text)
 | 
				
			||||||
 | 
					        self.index1 = text.index(self.index1)
 | 
				
			||||||
 | 
					        if self.index2:
 | 
				
			||||||
 | 
					            self.index2 = text.index(self.index2)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            self.index2 = text.index(self.index1 + " +1c")
 | 
				
			||||||
 | 
					        if text.compare(self.index2, ">", "end-1c"):
 | 
				
			||||||
 | 
					            # Don't delete the final newline
 | 
				
			||||||
 | 
					            self.index2 = text.index("end-1c")
 | 
				
			||||||
 | 
					        self.chars = text.get(self.index1, self.index2)
 | 
				
			||||||
 | 
					        text.delete(self.index1, self.index2)
 | 
				
			||||||
 | 
					        self.marks_after = self.save_marks(text)
 | 
				
			||||||
 | 
					        ##sys.__stderr__.write("do: %s\n" % self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def redo(self, text):
 | 
				
			||||||
 | 
					        text.mark_set('insert', self.index1)
 | 
				
			||||||
 | 
					        text.delete(self.index1, self.index2)
 | 
				
			||||||
 | 
					        self.set_marks(text, self.marks_after)
 | 
				
			||||||
 | 
					        text.see('insert')
 | 
				
			||||||
 | 
					        ##sys.__stderr__.write("redo: %s\n" % self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def undo(self, text):
 | 
				
			||||||
 | 
					        text.mark_set('insert', self.index1)
 | 
				
			||||||
 | 
					        text.insert(self.index1, self.chars)
 | 
				
			||||||
 | 
					        self.set_marks(text, self.marks_before)
 | 
				
			||||||
 | 
					        text.see('insert')
 | 
				
			||||||
 | 
					        ##sys.__stderr__.write("undo: %s\n" % self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CommandSequence(Command):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Wrapper for a sequence of undoable cmds to be undone/redone
 | 
				
			||||||
 | 
					    # as a unit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        self.cmds = []
 | 
				
			||||||
 | 
					        self.depth = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __repr__(self):
 | 
				
			||||||
 | 
					        s = self.__class__.__name__
 | 
				
			||||||
 | 
					        strs = []
 | 
				
			||||||
 | 
					        for cmd in self.cmds:
 | 
				
			||||||
 | 
					            strs.append("    " + `cmd`)
 | 
				
			||||||
 | 
					        return s + "(\n" + string.join(strs, ",\n") + "\n)"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __len__(self):
 | 
				
			||||||
 | 
					        return len(self.cmds)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def append(self, cmd):
 | 
				
			||||||
 | 
					        self.cmds.append(cmd)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getcmd(self, i):
 | 
				
			||||||
 | 
					        return self.cmds[i]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def redo(self, text):
 | 
				
			||||||
 | 
					        for cmd in self.cmds:
 | 
				
			||||||
 | 
					            cmd.redo(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def undo(self, text):
 | 
				
			||||||
 | 
					        cmds = self.cmds[:]
 | 
				
			||||||
 | 
					        cmds.reverse()
 | 
				
			||||||
 | 
					        for cmd in cmds:
 | 
				
			||||||
 | 
					            cmd.undo(text)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def bump_depth(self, incr=1):
 | 
				
			||||||
 | 
					        self.depth = self.depth + incr
 | 
				
			||||||
 | 
					        return self.depth
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    from Percolator import Percolator
 | 
				
			||||||
 | 
					    root = Tk()
 | 
				
			||||||
 | 
					    root.wm_protocol("WM_DELETE_WINDOW", root.quit)
 | 
				
			||||||
 | 
					    text = Text()
 | 
				
			||||||
 | 
					    text.pack()
 | 
				
			||||||
 | 
					    text.focus_set()
 | 
				
			||||||
 | 
					    p = Percolator(text)
 | 
				
			||||||
 | 
					    d = UndoDelegator()
 | 
				
			||||||
 | 
					    p.insertfilter(d)
 | 
				
			||||||
 | 
					    root.mainloop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										92
									
								
								Lib/idlelib/WidgetRedirector.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								Lib/idlelib/WidgetRedirector.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,92 @@
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class WidgetRedirector:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    """Support for redirecting arbitrary widget subcommands."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, widget):
 | 
				
			||||||
 | 
					        self.dict = {}
 | 
				
			||||||
 | 
					        self.widget = widget
 | 
				
			||||||
 | 
					        self.tk = tk = widget.tk
 | 
				
			||||||
 | 
					        w = widget._w
 | 
				
			||||||
 | 
					        self.orig = w + "_orig"
 | 
				
			||||||
 | 
					        tk.call("rename", w, self.orig)
 | 
				
			||||||
 | 
					        tk.createcommand(w, self.dispatch)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __repr__(self):
 | 
				
			||||||
 | 
					        return "WidgetRedirector(%s<%s>)" % (self.widget.__class__.__name__,
 | 
				
			||||||
 | 
					                                             self.widget._w)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self):
 | 
				
			||||||
 | 
					        for name in self.dict.keys():
 | 
				
			||||||
 | 
					            self.unregister(name)
 | 
				
			||||||
 | 
					        widget = self.widget; del self.widget
 | 
				
			||||||
 | 
					        orig = self.orig; del self.orig
 | 
				
			||||||
 | 
					        tk = widget.tk
 | 
				
			||||||
 | 
					        w = widget._w
 | 
				
			||||||
 | 
					        tk.deletecommand(w)
 | 
				
			||||||
 | 
					        tk.call("rename", orig, w)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def register(self, name, function):
 | 
				
			||||||
 | 
					        if self.dict.has_key(name):
 | 
				
			||||||
 | 
					            previous = dict[name]
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            previous = OriginalCommand(self, name)
 | 
				
			||||||
 | 
					        self.dict[name] = function
 | 
				
			||||||
 | 
					        setattr(self.widget, name, function)
 | 
				
			||||||
 | 
					        return previous
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def unregister(self, name):
 | 
				
			||||||
 | 
					        if self.dict.has_key(name):
 | 
				
			||||||
 | 
					            function = self.dict[name]
 | 
				
			||||||
 | 
					            del self.dict[name]
 | 
				
			||||||
 | 
					            if hasattr(self.widget, name):
 | 
				
			||||||
 | 
					                delattr(self.widget, name)
 | 
				
			||||||
 | 
					            return function
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, cmd, *args):
 | 
				
			||||||
 | 
					        m = self.dict.get(cmd)
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            if m:
 | 
				
			||||||
 | 
					                return apply(m, args)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                return self.tk.call((self.orig, cmd) + args)
 | 
				
			||||||
 | 
					        except TclError:
 | 
				
			||||||
 | 
					            return ""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class OriginalCommand:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, redir, name):
 | 
				
			||||||
 | 
					        self.redir = redir
 | 
				
			||||||
 | 
					        self.name = name
 | 
				
			||||||
 | 
					        self.tk = redir.tk
 | 
				
			||||||
 | 
					        self.orig = redir.orig
 | 
				
			||||||
 | 
					        self.tk_call = self.tk.call
 | 
				
			||||||
 | 
					        self.orig_and_name = (self.orig, self.name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __repr__(self):
 | 
				
			||||||
 | 
					        return "OriginalCommand(%s, %s)" % (`self.redir`, `self.name`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __call__(self, *args):
 | 
				
			||||||
 | 
					        return self.tk_call(self.orig_and_name + args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    root = Tk()
 | 
				
			||||||
 | 
					    text = Text()
 | 
				
			||||||
 | 
					    text.pack()
 | 
				
			||||||
 | 
					    text.focus_set()
 | 
				
			||||||
 | 
					    redir = WidgetRedirector(text)
 | 
				
			||||||
 | 
					    global orig_insert
 | 
				
			||||||
 | 
					    def my_insert(*args):
 | 
				
			||||||
 | 
					        print "insert", args
 | 
				
			||||||
 | 
					        apply(orig_insert, args)
 | 
				
			||||||
 | 
					    orig_insert = redir.register("insert", my_insert)
 | 
				
			||||||
 | 
					    root.mainloop()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == "__main__":
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
							
								
								
									
										85
									
								
								Lib/idlelib/WindowList.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								Lib/idlelib/WindowList.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,85 @@
 | 
				
			||||||
 | 
					from Tkinter import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class WindowList:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self):
 | 
				
			||||||
 | 
					        self.dict = {}
 | 
				
			||||||
 | 
					        self.callbacks = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add(self, window):
 | 
				
			||||||
 | 
					        window.after_idle(self.call_callbacks)
 | 
				
			||||||
 | 
					        self.dict[str(window)] = window
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def delete(self, window):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            del self.dict[str(window)]
 | 
				
			||||||
 | 
					        except KeyError:
 | 
				
			||||||
 | 
					            # Sometimes, destroy() is called twice
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					        self.call_callbacks()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def add_windows_to_menu(self,  menu):
 | 
				
			||||||
 | 
					        list = []
 | 
				
			||||||
 | 
					        for key in self.dict.keys():
 | 
				
			||||||
 | 
					            window = self.dict[key]
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                title = window.get_title()
 | 
				
			||||||
 | 
					            except TclError:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            list.append((title, window))
 | 
				
			||||||
 | 
					        list.sort()
 | 
				
			||||||
 | 
					        for title, window in list:
 | 
				
			||||||
 | 
					            if title == "Python Shell":
 | 
				
			||||||
 | 
					                # Hack -- until we have a better way to this
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            menu.add_command(label=title, command=window.wakeup)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def register_callback(self, callback):
 | 
				
			||||||
 | 
					        self.callbacks.append(callback)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def unregister_callback(self, callback):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					           self.callbacks.remove(callback)
 | 
				
			||||||
 | 
					        except ValueError:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def call_callbacks(self):
 | 
				
			||||||
 | 
					        for callback in self.callbacks:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                callback()
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                print "warning: callback failed in WindowList", \
 | 
				
			||||||
 | 
					                      sys.exc_type, ":", sys.exc_value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					registry = WindowList()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					add_windows_to_menu = registry.add_windows_to_menu
 | 
				
			||||||
 | 
					register_callback = registry.register_callback
 | 
				
			||||||
 | 
					unregister_callback = registry.unregister_callback
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ListedToplevel(Toplevel):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, master, **kw):
 | 
				
			||||||
 | 
					        Toplevel.__init__(self, master, kw)
 | 
				
			||||||
 | 
					        registry.add(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def destroy(self):
 | 
				
			||||||
 | 
					        registry.delete(self)
 | 
				
			||||||
 | 
					        Toplevel.destroy(self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def get_title(self):
 | 
				
			||||||
 | 
					        # Subclass can override
 | 
				
			||||||
 | 
					        return self.wm_title()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def wakeup(self):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            if self.wm_state() == "iconic":
 | 
				
			||||||
 | 
					                self.wm_deiconify()
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                self.tkraise()
 | 
				
			||||||
 | 
					            self.focus_set()
 | 
				
			||||||
 | 
					        except TclError:
 | 
				
			||||||
 | 
					            # This can happen when the window menu was torn off.
 | 
				
			||||||
 | 
					            # Simply ignore it.
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
							
								
								
									
										46
									
								
								Lib/idlelib/ZoomHeight.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								Lib/idlelib/ZoomHeight.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,46 @@
 | 
				
			||||||
 | 
					# Sample extension: zoom a window to maximum height
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZoomHeight:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    menudefs = [
 | 
				
			||||||
 | 
					        ('windows', [
 | 
				
			||||||
 | 
					            ('_Zoom Height', '<<zoom-height>>'),
 | 
				
			||||||
 | 
					         ])
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    windows_keydefs = {
 | 
				
			||||||
 | 
					        '<<zoom-height>>': ['<Alt-F2>'],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    unix_keydefs = {
 | 
				
			||||||
 | 
					        '<<zoom-height>>': ['<Control-x><Control-z>'],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, editwin):
 | 
				
			||||||
 | 
					        self.editwin = editwin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def zoom_height_event(self, event):
 | 
				
			||||||
 | 
					        top = self.editwin.top
 | 
				
			||||||
 | 
					        zoom_height(top)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def zoom_height(top):
 | 
				
			||||||
 | 
					    geom = top.wm_geometry()
 | 
				
			||||||
 | 
					    m = re.match(r"(\d+)x(\d+)\+(-?\d+)\+(-?\d+)", geom)
 | 
				
			||||||
 | 
					    if not m:
 | 
				
			||||||
 | 
					        top.bell()
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					    width, height, x, y = map(int, m.groups())
 | 
				
			||||||
 | 
					    newheight = top.winfo_screenheight()
 | 
				
			||||||
 | 
					    if sys.platform == 'win32':
 | 
				
			||||||
 | 
					        newy = 0
 | 
				
			||||||
 | 
					        newheight = newheight - 72
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        newy = 24
 | 
				
			||||||
 | 
					        newheight = newheight - 96
 | 
				
			||||||
 | 
					    if height >= newheight:
 | 
				
			||||||
 | 
					        newgeom = ""
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        newgeom = "%dx%d+%d+%d" % (width, newheight, x, newy)
 | 
				
			||||||
 | 
					    top.wm_geometry(newgeom)
 | 
				
			||||||
							
								
								
									
										1
									
								
								Lib/idlelib/__init__.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Lib/idlelib/__init__.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					# Dummy file to make this a potential package.
 | 
				
			||||||
							
								
								
									
										3
									
								
								Lib/idlelib/config-unix.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								Lib/idlelib/config-unix.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					[EditorWindow]
 | 
				
			||||||
 | 
					font-name= courier
 | 
				
			||||||
 | 
					font-size= 10
 | 
				
			||||||
							
								
								
									
										3
									
								
								Lib/idlelib/config-win.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								Lib/idlelib/config-win.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					[EditorWindow]
 | 
				
			||||||
 | 
					font-name: courier new
 | 
				
			||||||
 | 
					font-size: 10
 | 
				
			||||||
							
								
								
									
										66
									
								
								Lib/idlelib/config.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								Lib/idlelib/config.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,66 @@
 | 
				
			||||||
 | 
					# IDLE reads several config files to determine user preferences.  This 
 | 
				
			||||||
 | 
					# file is the default config file.  When IDLE starts, it will look in
 | 
				
			||||||
 | 
					# the following four files in order:
 | 
				
			||||||
 | 
					#     config.txt                      the default config file
 | 
				
			||||||
 | 
					#     config-[win/unix/mac].txt       the generic platform config file
 | 
				
			||||||
 | 
					#     config-[sys.platform].txt       the specific platform config file
 | 
				
			||||||
 | 
					#     ~/.idle                         the user config file
 | 
				
			||||||
 | 
					# XXX what about Windows?
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# The last definition of each option is used.  For example, you can
 | 
				
			||||||
 | 
					# override the default window size (80x24) by defining width and
 | 
				
			||||||
 | 
					# height options in the EditorWindow section of your ~/.idle file
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# IDLE extensions can be enabled and disabled by adding them to one of
 | 
				
			||||||
 | 
					# the config files.  To enable an extension, create a section with the
 | 
				
			||||||
 | 
					# same name as the extension, e.g. the [ParenMatch] section below.  To
 | 
				
			||||||
 | 
					# disable an extension, either remove the section or add the the
 | 
				
			||||||
 | 
					# enable option with the value 0.  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[EditorWindow]
 | 
				
			||||||
 | 
					width= 80
 | 
				
			||||||
 | 
					height= 24
 | 
				
			||||||
 | 
					# fonts defined in config-[win/unix].txt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[Colors]
 | 
				
			||||||
 | 
					normal-foreground= black
 | 
				
			||||||
 | 
					normal-background= white
 | 
				
			||||||
 | 
					# These color types are not explicitly defined= sync, todo, stdin
 | 
				
			||||||
 | 
					keyword-foreground= #ff7700
 | 
				
			||||||
 | 
					comment-foreground= #dd0000
 | 
				
			||||||
 | 
					string-foreground= #00aa00
 | 
				
			||||||
 | 
					definition-foreground= #0000ff
 | 
				
			||||||
 | 
					hilite-foreground= #000068
 | 
				
			||||||
 | 
					hilite-background= #006868
 | 
				
			||||||
 | 
					break-foreground= #ff7777
 | 
				
			||||||
 | 
					hit-foreground= #ffffff
 | 
				
			||||||
 | 
					hit-background= #000000
 | 
				
			||||||
 | 
					stdout-foreground= blue
 | 
				
			||||||
 | 
					stderr-foreground= red
 | 
				
			||||||
 | 
					console-foreground= #770000
 | 
				
			||||||
 | 
					error-background= #ff7777
 | 
				
			||||||
 | 
					cursor-background= black
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[SearchBinding]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[AutoIndent]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[AutoExpand]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[FormatParagraph]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[ZoomHeight]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[ScriptBinding]    # disabled in favor of ExecBinding
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[ExecBinding]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[CallTips]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					[ParenMatch]
 | 
				
			||||||
 | 
					enable= 0
 | 
				
			||||||
 | 
					style= expression
 | 
				
			||||||
 | 
					flash-delay= 500
 | 
				
			||||||
 | 
					bell= 1
 | 
				
			||||||
 | 
					hilite-foreground= black
 | 
				
			||||||
 | 
					hilite-background= #43cd80
 | 
				
			||||||
							
								
								
									
										93
									
								
								Lib/idlelib/eventparse.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								Lib/idlelib/eventparse.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,93 @@
 | 
				
			||||||
 | 
					#! /usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""Parse event definitions out of comments in source files."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import getopt
 | 
				
			||||||
 | 
					import glob
 | 
				
			||||||
 | 
					import fileinput
 | 
				
			||||||
 | 
					import pprint
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    hits = []
 | 
				
			||||||
 | 
					    sublist = []
 | 
				
			||||||
 | 
					    args = sys.argv[1:]
 | 
				
			||||||
 | 
					    if not args:
 | 
				
			||||||
 | 
					        args = filter(lambda s: 'A' <= s[0] <= 'Z', glob.glob("*.py"))
 | 
				
			||||||
 | 
					        if not args:
 | 
				
			||||||
 | 
					            print "No arguments, no [A-Z]*.py files."
 | 
				
			||||||
 | 
					            return 1
 | 
				
			||||||
 | 
					    for line in fileinput.input(args):
 | 
				
			||||||
 | 
					        if line[:2] == '#$':
 | 
				
			||||||
 | 
					            if not sublist:
 | 
				
			||||||
 | 
					                sublist.append('file %s' % fileinput.filename())
 | 
				
			||||||
 | 
					                sublist.append('line %d' % fileinput.lineno())
 | 
				
			||||||
 | 
					            sublist.append(string.strip(line[2:-1]))
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if sublist:
 | 
				
			||||||
 | 
					                hits.append(sublist)
 | 
				
			||||||
 | 
					                sublist = []
 | 
				
			||||||
 | 
					    if sublist:
 | 
				
			||||||
 | 
					        hits.append(sublist)
 | 
				
			||||||
 | 
					        sublist = []
 | 
				
			||||||
 | 
					    dd = {}
 | 
				
			||||||
 | 
					    for sublist in hits:
 | 
				
			||||||
 | 
					        d = {}
 | 
				
			||||||
 | 
					        for line in sublist:
 | 
				
			||||||
 | 
					            words = string.split(line, None, 1)
 | 
				
			||||||
 | 
					            if len(words) != 2:
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            tag = words[0]
 | 
				
			||||||
 | 
					            l = d.get(tag, [])
 | 
				
			||||||
 | 
					            l.append(words[1])
 | 
				
			||||||
 | 
					            d[tag] = l
 | 
				
			||||||
 | 
					        if d.has_key('event'):
 | 
				
			||||||
 | 
					            keys = d['event']
 | 
				
			||||||
 | 
					            if len(keys) != 1:
 | 
				
			||||||
 | 
					                print "Multiple event keys in", d
 | 
				
			||||||
 | 
					                print 'File "%s", line %d' % (d['file'], d['line'])
 | 
				
			||||||
 | 
					            key = keys[0]
 | 
				
			||||||
 | 
					            if dd.has_key(key):
 | 
				
			||||||
 | 
					                print "Duplicate event in", d
 | 
				
			||||||
 | 
					                print 'File "%s", line %d' % (d['file'], d['line'])
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            dd[key] = d
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            print "No event key in", d
 | 
				
			||||||
 | 
					            print 'File "%s", line %d' % (d['file'], d['line'])
 | 
				
			||||||
 | 
					    winevents = getevents(dd, "win")
 | 
				
			||||||
 | 
					    unixevents = getevents(dd, "unix")
 | 
				
			||||||
 | 
					    save = sys.stdout
 | 
				
			||||||
 | 
					    f = open("keydefs.py", "w")
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        sys.stdout = f
 | 
				
			||||||
 | 
					        print "windows_keydefs = \\"
 | 
				
			||||||
 | 
					        pprint.pprint(winevents)
 | 
				
			||||||
 | 
					        print
 | 
				
			||||||
 | 
					        print "unix_keydefs = \\"
 | 
				
			||||||
 | 
					        pprint.pprint(unixevents)
 | 
				
			||||||
 | 
					    finally:
 | 
				
			||||||
 | 
					        sys.stdout = save
 | 
				
			||||||
 | 
					    f.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def getevents(dd, key):
 | 
				
			||||||
 | 
					    res = {}
 | 
				
			||||||
 | 
					    events = dd.keys()
 | 
				
			||||||
 | 
					    events.sort()
 | 
				
			||||||
 | 
					    for e in events:
 | 
				
			||||||
 | 
					        d = dd[e]
 | 
				
			||||||
 | 
					        if d.has_key(key) or d.has_key("all"):
 | 
				
			||||||
 | 
					            list = []
 | 
				
			||||||
 | 
					            for x in d.get(key, []) + d.get("all", []):
 | 
				
			||||||
 | 
					                list.append(x)
 | 
				
			||||||
 | 
					                if key == "unix" and x[:5] == "<Alt-":
 | 
				
			||||||
 | 
					                    x = "<Meta-" + x[5:]
 | 
				
			||||||
 | 
					                    list.append(x)
 | 
				
			||||||
 | 
					            res[e] = list
 | 
				
			||||||
 | 
					    return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    sys.exit(main())
 | 
				
			||||||
							
								
								
									
										106
									
								
								Lib/idlelib/extend.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								Lib/idlelib/extend.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,106 @@
 | 
				
			||||||
 | 
					Writing an IDLE extension
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					An IDLE extension can define new key bindings and menu entries for IDLE
 | 
				
			||||||
 | 
					edit windows.  There is a simple mechanism to load extensions when IDLE
 | 
				
			||||||
 | 
					starts up and to attach them to each edit window. (It is also possible
 | 
				
			||||||
 | 
					to make other changes to IDLE, but this must be done by editing the IDLE
 | 
				
			||||||
 | 
					source code.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The list of extensions loaded at startup time is configured by editing
 | 
				
			||||||
 | 
					the file extend.py; see below for details.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					An IDLE extension is defined by a class.  Methods of the class define
 | 
				
			||||||
 | 
					actions that are invoked by those bindings or menu entries. Class (or
 | 
				
			||||||
 | 
					instance) variables define the bindings and menu additions; these are
 | 
				
			||||||
 | 
					automatically applied by IDLE when the extension is linked to an edit
 | 
				
			||||||
 | 
					window.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					An IDLE extension class is instantiated with a single argument,
 | 
				
			||||||
 | 
					`editwin', an EditorWindow instance. The extension cannot assume much
 | 
				
			||||||
 | 
					about this argument, but it is guarateed to have the following instance
 | 
				
			||||||
 | 
					variables:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    text	a Text instance (a widget)
 | 
				
			||||||
 | 
					    io		an IOBinding instance (more about this later)
 | 
				
			||||||
 | 
					    flist	the FileList instance (shared by all edit windows)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(There are a few more, but they are rarely useful.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The extension class must not bind key events.  Rather, it must define
 | 
				
			||||||
 | 
					one or more virtual events, e.g. <<zoom-height>>, and corresponding
 | 
				
			||||||
 | 
					methods, e.g. zoom_height_event(), and have one or more class (or instance)
 | 
				
			||||||
 | 
					variables that define mappings between virtual events and key sequences,
 | 
				
			||||||
 | 
					e.g. <Alt-F2>.  When the extension is loaded, these key sequences will
 | 
				
			||||||
 | 
					be bound to the corresponding virtual events, and the virtual events
 | 
				
			||||||
 | 
					will be bound to the corresponding methods.  (This indirection is done
 | 
				
			||||||
 | 
					so that the key bindings can easily be changed, and so that other
 | 
				
			||||||
 | 
					sources of virtual events can exist, such as menu entries.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The following class or instance variables are used to define key
 | 
				
			||||||
 | 
					bindings for virtual events:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    keydefs		for all platforms
 | 
				
			||||||
 | 
					    mac_keydefs		for Macintosh
 | 
				
			||||||
 | 
					    windows_keydefs	for Windows
 | 
				
			||||||
 | 
					    unix_keydefs	for Unix (and other platforms)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each of these variables, if it exists, must be a dictionary whose
 | 
				
			||||||
 | 
					keys are virtual events, and whose values are lists of key sequences.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					An extension can define menu entries in a similar fashion.  This is done
 | 
				
			||||||
 | 
					with a class or instance variable named menudefs; it should be a list of
 | 
				
			||||||
 | 
					pair, where each pair is a menu name (lowercase) and a list of menu
 | 
				
			||||||
 | 
					entries. Each menu entry is either None (to insert a separator entry) or
 | 
				
			||||||
 | 
					a pair of strings (menu_label, virtual_event).  Here, menu_label is the
 | 
				
			||||||
 | 
					label of the menu entry, and virtual_event is the virtual event to be
 | 
				
			||||||
 | 
					generated when the entry is selected.  An underscore in the menu label
 | 
				
			||||||
 | 
					is removed; the character following the underscore is displayed
 | 
				
			||||||
 | 
					underlined, to indicate the shortcut character (for Windows).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					At the moment, extensions cannot define whole new menus; they must
 | 
				
			||||||
 | 
					define entries in existing menus.  Some menus are not present on some
 | 
				
			||||||
 | 
					windows; such entry definitions are then ignored, but the key bindings
 | 
				
			||||||
 | 
					are still applied.  (This should probably be refined in the future.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Here is a complete example example:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ZoomHeight:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    menudefs = [
 | 
				
			||||||
 | 
					        ('edit', [
 | 
				
			||||||
 | 
					            None, # Separator
 | 
				
			||||||
 | 
					            ('_Zoom Height', '<<zoom-height>>'),
 | 
				
			||||||
 | 
					         ])
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    windows_keydefs = {
 | 
				
			||||||
 | 
					        '<<zoom-height>>': ['<Alt-F2>'],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    unix_keydefs = {
 | 
				
			||||||
 | 
					        '<<zoom-height>>': ['<Control-z><Control-z>'],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, editwin):
 | 
				
			||||||
 | 
					        self.editwin = editwin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def zoom_height_event(self, event):
 | 
				
			||||||
 | 
					        "...Do what you want here..."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The final piece of the puzzle is the file "extend.py", which contains a
 | 
				
			||||||
 | 
					simple table used to configure the loading of extensions.  This file
 | 
				
			||||||
 | 
					currently contains a single list variable named "standard", which is a
 | 
				
			||||||
 | 
					list of extension names that are to be loaded.  (In the future, other
 | 
				
			||||||
 | 
					configuration variables may be added to this module.)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Extensions can define key bindings and menu entries that reference
 | 
				
			||||||
 | 
					events they don't implement (including standard events); however this is
 | 
				
			||||||
 | 
					not recommended (and may be forbidden in the future).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Extensions are not required to define menu entries for all events they
 | 
				
			||||||
 | 
					implement.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Note: in order to change key bindings, you must currently edit the file
 | 
				
			||||||
 | 
					keydefs.  It contains two dictionaries named and formatted like the
 | 
				
			||||||
 | 
					keydefs dictionaries described above, one for the Unix bindings and one
 | 
				
			||||||
 | 
					for the Windows bindings.  In the future, a better mechanism will be
 | 
				
			||||||
 | 
					provided.
 | 
				
			||||||
							
								
								
									
										155
									
								
								Lib/idlelib/help.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								Lib/idlelib/help.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,155 @@
 | 
				
			||||||
 | 
					[See end for tips.]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Click on the dotted line at the top of a menu to "tear it off": a
 | 
				
			||||||
 | 
					separate window containing the menu is created.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					File menu:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						New window -- create a new editing window
 | 
				
			||||||
 | 
						Open... -- open an existing file
 | 
				
			||||||
 | 
						Open module... -- open an existing module (searches sys.path)
 | 
				
			||||||
 | 
						Class browser -- show classes and methods in current file
 | 
				
			||||||
 | 
						Path browser -- show sys.path directories, modules, classes
 | 
				
			||||||
 | 
							and methods
 | 
				
			||||||
 | 
						---
 | 
				
			||||||
 | 
						Save -- save current window to the associated file (unsaved
 | 
				
			||||||
 | 
							windows have a * before and after the window title)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Save As... -- save current window to new file, which becomes
 | 
				
			||||||
 | 
							the associated file
 | 
				
			||||||
 | 
						Save Copy As... -- save current window to different file
 | 
				
			||||||
 | 
							without changing the associated file
 | 
				
			||||||
 | 
						---
 | 
				
			||||||
 | 
						Close -- close current window (asks to save if unsaved)
 | 
				
			||||||
 | 
						Exit -- close all windows and quit IDLE (asks to save if unsaved)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Edit menu:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Undo -- Undo last change to current window (max 1000 changes)
 | 
				
			||||||
 | 
						Redo -- Redo last undone change to current window
 | 
				
			||||||
 | 
						---
 | 
				
			||||||
 | 
						Cut -- Copy selection into system-wide clipboard; then delete selection
 | 
				
			||||||
 | 
						Copy -- Copy selection into system-wide clipboard
 | 
				
			||||||
 | 
						Paste -- Insert system-wide clipboard into window
 | 
				
			||||||
 | 
						Select All -- Select the entire contents of the edit buffer
 | 
				
			||||||
 | 
						---
 | 
				
			||||||
 | 
						Find... -- Open a search dialog box with many options
 | 
				
			||||||
 | 
						Find again -- Repeat last search
 | 
				
			||||||
 | 
						Find selection -- Search for the string in the selection
 | 
				
			||||||
 | 
						Find in Files... -- Open a search dialog box for searching files
 | 
				
			||||||
 | 
						Replace... -- Open a search-and-replace dialog box
 | 
				
			||||||
 | 
						Go to line -- Ask for a line number and show that line
 | 
				
			||||||
 | 
						---
 | 
				
			||||||
 | 
						Indent region -- Shift selected lines right 4 spaces
 | 
				
			||||||
 | 
						Dedent region -- Shift selected lines left 4 spaces
 | 
				
			||||||
 | 
						Comment out region -- Insert ## in front of selected lines
 | 
				
			||||||
 | 
						Uncomment region -- Remove leading # or ## from selected lines
 | 
				
			||||||
 | 
						Tabify region -- Turns *leading* stretches of spaces into tabs
 | 
				
			||||||
 | 
						Untabify region -- Turn *all* tabs into the right number of spaces
 | 
				
			||||||
 | 
						Expand word -- Expand the word you have typed to match another
 | 
				
			||||||
 | 
							word in the same buffer; repeat to get a different expansion
 | 
				
			||||||
 | 
						Format Paragraph -- Reformat the current blank-line-separated paragraph
 | 
				
			||||||
 | 
						---
 | 
				
			||||||
 | 
						Import module -- Import or reload the current module
 | 
				
			||||||
 | 
						Run script -- Execute the current file in the __main__ namespace
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Windows menu:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Zoom Height -- toggles the window between normal size (24x80)
 | 
				
			||||||
 | 
						and maximum height.
 | 
				
			||||||
 | 
						---
 | 
				
			||||||
 | 
						The rest of this menu lists the names of all open windows;
 | 
				
			||||||
 | 
						select one to bring it to the foreground (deiconifying it if
 | 
				
			||||||
 | 
						necessary).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Debug menu (in the Python Shell window only):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Go to file/line -- look around the insert point for a filename
 | 
				
			||||||
 | 
							and linenumber, open the file, and show the line
 | 
				
			||||||
 | 
						Open stack viewer -- show the stack traceback of the last exception
 | 
				
			||||||
 | 
						Debugger toggle -- Run commands in the shell under the debugger
 | 
				
			||||||
 | 
						JIT Stack viewer toggle -- Open stack viewer on traceback
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Basic editing and navigation:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Backspace deletes to the left; DEL deletes to the right
 | 
				
			||||||
 | 
						Arrow keys and Page Up/Down to move around
 | 
				
			||||||
 | 
						Home/End go to begin/end of line
 | 
				
			||||||
 | 
						Control-Home/End go to begin/end of file
 | 
				
			||||||
 | 
						Some Emacs bindings may also work, e.g. ^B/^P/^A/^E/^D/^L
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Automatic indentation:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						After a block-opening statement, the next line is indented by
 | 
				
			||||||
 | 
						4 spaces (in the Python Shell window by one tab).  After
 | 
				
			||||||
 | 
						certain keywords (break, return etc.) the next line is
 | 
				
			||||||
 | 
						dedented.  In leading indentation, Backspace deletes up to 4
 | 
				
			||||||
 | 
						spaces if they are there.  Tab inserts 1-4 spaces (in the
 | 
				
			||||||
 | 
						Python Shell window one tab).  See also the indent/dedent
 | 
				
			||||||
 | 
						region commands in the edit menu.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Python Shell window:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						^C interrupts executing command
 | 
				
			||||||
 | 
						^D sends end-of-file; closes window if typed at >>> prompt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Command history:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Alt-p retrieves previous command matching what you have typed
 | 
				
			||||||
 | 
						Alt-n retrieves next
 | 
				
			||||||
 | 
						Return while on any previous command retrieves that command
 | 
				
			||||||
 | 
						Alt-/ (Expand word) is also useful here
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Syntax colors:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						The coloring is applied in a background "thread", so you may
 | 
				
			||||||
 | 
						occasionally see uncolorized text.  To change the color
 | 
				
			||||||
 | 
						scheme, edit the ColorPrefs class in IdlePrefs.py.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Python syntax colors:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Keywords	orange
 | 
				
			||||||
 | 
						Strings		green
 | 
				
			||||||
 | 
						Comments	red
 | 
				
			||||||
 | 
						Definitions	blue
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Shell colors:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Console output	brown
 | 
				
			||||||
 | 
						stdout		blue
 | 
				
			||||||
 | 
						stderr		dark green
 | 
				
			||||||
 | 
						stdin		black
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Other preferences:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						To change the font on Windows, open EditorWindow.py and change
 | 
				
			||||||
 | 
						    text['font'] = ("lucida console", 8)
 | 
				
			||||||
 | 
						to, e.g.,
 | 
				
			||||||
 | 
						    text['font'] = ("courier new", 10)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						To change keyboard bindings, edit Bindings.py
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Command line usage:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						idle.py [-c command] [-d] [-e] [-s] [-t title] [arg] ...
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						-c command  run this command
 | 
				
			||||||
 | 
						-d          enable debugger
 | 
				
			||||||
 | 
						-e          edit mode; arguments are files to be edited
 | 
				
			||||||
 | 
						-s          run $IDLESTARTUP or $PYTHONSTARTUP first
 | 
				
			||||||
 | 
						-t title    set title of shell window
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						If there are arguments:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    If -e is used, arguments are files opened for editing and
 | 
				
			||||||
 | 
						    sys.argv reflects the arguments passed to IDLE itself.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    Otherwise, if -c is used, all arguments are placed in
 | 
				
			||||||
 | 
						    sys.argv[1:...], with sys.argv[0] set to '-c'.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						    Otherwise, if neither -e nor -c is used, the first
 | 
				
			||||||
 | 
						    argument is a script which is executed with the remaining
 | 
				
			||||||
 | 
						    arguments in sys.argv[1:...]  and sys.argv[0] set to the
 | 
				
			||||||
 | 
						    script name.  If the script name is '-', no script is
 | 
				
			||||||
 | 
						    executed but an interactive Python session is started; the
 | 
				
			||||||
 | 
						    arguments are still available in sys.argv.
 | 
				
			||||||
							
								
								
									
										3
									
								
								Lib/idlelib/idle.bat
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										3
									
								
								Lib/idlelib/idle.bat
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					@echo off
 | 
				
			||||||
 | 
					rem Working IDLE bat for Windows - uses start instead of absolute pathname
 | 
				
			||||||
 | 
					start idle.pyw %1 %2 %3 %4 %5 %6 %7 %8 %9
 | 
				
			||||||
							
								
								
									
										12
									
								
								Lib/idlelib/idle.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Lib/idlelib/idle.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					#! /usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import IdleConf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					idle_dir = os.path.split(sys.argv[0])[0]
 | 
				
			||||||
 | 
					IdleConf.load(idle_dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# defer importing Pyshell until IdleConf is loaded
 | 
				
			||||||
 | 
					import PyShell
 | 
				
			||||||
 | 
					PyShell.main()
 | 
				
			||||||
							
								
								
									
										12
									
								
								Lib/idlelib/idle.pyw
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Lib/idlelib/idle.pyw
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,12 @@
 | 
				
			||||||
 | 
					#! /usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import IdleConf
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					idle_dir = os.path.split(sys.argv[0])[0]
 | 
				
			||||||
 | 
					IdleConf.load(idle_dir)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# defer importing Pyshell until IdleConf is loaded
 | 
				
			||||||
 | 
					import PyShell
 | 
				
			||||||
 | 
					PyShell.main()
 | 
				
			||||||
							
								
								
									
										1
									
								
								Lib/idlelib/idlever.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								Lib/idlelib/idlever.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1 @@
 | 
				
			||||||
 | 
					IDLE_VERSION = "0.5"
 | 
				
			||||||
							
								
								
									
										55
									
								
								Lib/idlelib/keydefs.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								Lib/idlelib/keydefs.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,55 @@
 | 
				
			||||||
 | 
					windows_keydefs = \
 | 
				
			||||||
 | 
					{'<<Copy>>': ['<Control-c>'],
 | 
				
			||||||
 | 
					 '<<Cut>>': ['<Control-x>'],
 | 
				
			||||||
 | 
					 '<<Paste>>': ['<Control-v>'],
 | 
				
			||||||
 | 
					 '<<beginning-of-line>>': ['<Control-a>', '<Home>'],
 | 
				
			||||||
 | 
					 '<<center-insert>>': ['<Control-l>'],
 | 
				
			||||||
 | 
					 '<<close-all-windows>>': ['<Control-q>'],
 | 
				
			||||||
 | 
					 '<<close-window>>': ['<Alt-F4>'],
 | 
				
			||||||
 | 
					 '<<dump-undo-state>>': ['<Control-backslash>'],
 | 
				
			||||||
 | 
					 '<<end-of-file>>': ['<Control-d>'],
 | 
				
			||||||
 | 
					 '<<python-docs>>': ['<F1>'],
 | 
				
			||||||
 | 
					 '<<history-next>>': ['<Alt-n>'],
 | 
				
			||||||
 | 
					 '<<history-previous>>': ['<Alt-p>'],
 | 
				
			||||||
 | 
					 '<<interrupt-execution>>': ['<Control-c>'],
 | 
				
			||||||
 | 
					 '<<open-class-browser>>': ['<Alt-c>'],
 | 
				
			||||||
 | 
					 '<<open-module>>': ['<Alt-m>'],
 | 
				
			||||||
 | 
					 '<<open-new-window>>': ['<Control-n>'],
 | 
				
			||||||
 | 
					 '<<open-window-from-file>>': ['<Control-o>'],
 | 
				
			||||||
 | 
					 '<<plain-newline-and-indent>>': ['<Control-j>'],
 | 
				
			||||||
 | 
					 '<<redo>>': ['<Control-y>'],
 | 
				
			||||||
 | 
					 '<<remove-selection>>': ['<Escape>'],
 | 
				
			||||||
 | 
					 '<<save-copy-of-window-as-file>>': ['<Alt-Shift-s>'],
 | 
				
			||||||
 | 
					 '<<save-window-as-file>>': ['<Alt-s>'],
 | 
				
			||||||
 | 
					 '<<save-window>>': ['<Control-s>'],
 | 
				
			||||||
 | 
					 '<<select-all>>': ['<Alt-a>'],
 | 
				
			||||||
 | 
					 '<<toggle-auto-coloring>>': ['<Control-slash>'],
 | 
				
			||||||
 | 
					 '<<undo>>': ['<Control-z>']}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					unix_keydefs = \
 | 
				
			||||||
 | 
					{'<<Copy>>': ['<Alt-w>', '<Meta-w>'],
 | 
				
			||||||
 | 
					 '<<Cut>>': ['<Control-w>'],
 | 
				
			||||||
 | 
					 '<<Paste>>': ['<Control-y>'],
 | 
				
			||||||
 | 
					 '<<beginning-of-line>>': ['<Control-a>', '<Home>'],
 | 
				
			||||||
 | 
					 '<<center-insert>>': ['<Control-l>'],
 | 
				
			||||||
 | 
					 '<<close-all-windows>>': ['<Control-x><Control-c>'],
 | 
				
			||||||
 | 
					 '<<close-window>>': ['<Control-x><Control-0>', '<Control-x><Key-0>'],
 | 
				
			||||||
 | 
					 '<<do-nothing>>': ['<Control-x>'],
 | 
				
			||||||
 | 
					 '<<dump-undo-state>>': ['<Control-backslash>'],
 | 
				
			||||||
 | 
					 '<<end-of-file>>': ['<Control-d>'],
 | 
				
			||||||
 | 
					 '<<help>>': ['<F1>'],
 | 
				
			||||||
 | 
					 '<<history-next>>': ['<Alt-n>', '<Meta-n>'],
 | 
				
			||||||
 | 
					 '<<history-previous>>': ['<Alt-p>', '<Meta-p>'],
 | 
				
			||||||
 | 
					 '<<interrupt-execution>>': ['<Control-c>'],
 | 
				
			||||||
 | 
					 '<<open-class-browser>>': ['<Control-x><Control-b>'],
 | 
				
			||||||
 | 
					 '<<open-module>>': ['<Control-x><Control-m>'],
 | 
				
			||||||
 | 
					 '<<open-new-window>>': ['<Control-x><Control-n>'],
 | 
				
			||||||
 | 
					 '<<open-window-from-file>>': ['<Control-x><Control-f>'],
 | 
				
			||||||
 | 
					 '<<plain-newline-and-indent>>': ['<Control-j>'],
 | 
				
			||||||
 | 
					 '<<redo>>': ['<Alt-z>', '<Meta-z>'],
 | 
				
			||||||
 | 
					 '<<save-copy-of-window-as-file>>': ['<Control-x><w>'],
 | 
				
			||||||
 | 
					 '<<save-window-as-file>>': ['<Control-x><Control-w>'],
 | 
				
			||||||
 | 
					 '<<save-window>>': ['<Control-x><Control-s>'],
 | 
				
			||||||
 | 
					 '<<select-all>>': ['<Alt-a>', '<Meta-a>'],
 | 
				
			||||||
 | 
					 '<<toggle-auto-coloring>>': ['<Control-slash>'],
 | 
				
			||||||
 | 
					 '<<undo>>': ['<Control-z>']}
 | 
				
			||||||
							
								
								
									
										64
									
								
								Lib/idlelib/loader.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								Lib/idlelib/loader.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,64 @@
 | 
				
			||||||
 | 
					# Everything is done inside the loader function so that no other names
 | 
				
			||||||
 | 
					# are placed in the global namespace.  Before user code is executed,
 | 
				
			||||||
 | 
					# even this name is unbound.
 | 
				
			||||||
 | 
					def loader():
 | 
				
			||||||
 | 
					    import sys, os, protocol, threading, time
 | 
				
			||||||
 | 
					    import Remote
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					##  Use to debug the loading process itself:
 | 
				
			||||||
 | 
					##    sys.stdout = open('c:\\windows\\desktop\\stdout.txt','a')
 | 
				
			||||||
 | 
					##    sys.stderr = open('c:\\windows\\desktop\\stderr.txt','a')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Ensure that there is absolutely no pollution of the global
 | 
				
			||||||
 | 
					    # namespace by deleting the global name of this function.
 | 
				
			||||||
 | 
					    global loader
 | 
				
			||||||
 | 
					    del loader
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Connect to IDLE
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        client = protocol.Client()
 | 
				
			||||||
 | 
					    except protocol.connectionLost, cL:
 | 
				
			||||||
 | 
					        print 'loader: Unable to connect to IDLE', cL
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Connect to an ExecBinding object that needs our help.  If
 | 
				
			||||||
 | 
					    # the user is starting multiple programs right now, we might get a
 | 
				
			||||||
 | 
					    # different one than the one that started us.  Proving that's okay is
 | 
				
			||||||
 | 
					    # left as an exercise to the reader.  (HINT:  Twelve, by the pigeonhole
 | 
				
			||||||
 | 
					    # principle)
 | 
				
			||||||
 | 
					    ExecBinding = client.getobject('ExecBinding')
 | 
				
			||||||
 | 
					    if not ExecBinding:
 | 
				
			||||||
 | 
					        print "loader: IDLE does not need me."
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # All of our input and output goes through ExecBinding.
 | 
				
			||||||
 | 
					    sys.stdin  = Remote.pseudoIn( ExecBinding.readline )
 | 
				
			||||||
 | 
					    sys.stdout = Remote.pseudoOut( ExecBinding.write.void, tag="stdout" )
 | 
				
			||||||
 | 
					    sys.stderr = Remote.pseudoOut( ExecBinding.write.void, tag="stderr" )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Create a Remote object and start it running.
 | 
				
			||||||
 | 
					    remote = Remote.Remote(globals(), ExecBinding)
 | 
				
			||||||
 | 
					    rthread = threading.Thread(target=remote.mainloop)
 | 
				
			||||||
 | 
					    rthread.setDaemon(1)
 | 
				
			||||||
 | 
					    rthread.start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Block until either the client or the user program stops
 | 
				
			||||||
 | 
					    user = rthread.isAlive
 | 
				
			||||||
 | 
					    while user and client.isAlive():
 | 
				
			||||||
 | 
					        time.sleep(0.025)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if not user():
 | 
				
			||||||
 | 
					          user = hasattr(sys, "ready_to_exit") and sys.ready_to_exit
 | 
				
			||||||
 | 
					          for t in threading.enumerate():
 | 
				
			||||||
 | 
					            if not t.isDaemon() and t.isAlive() and t!=threading.currentThread():
 | 
				
			||||||
 | 
					              user = t.isAlive
 | 
				
			||||||
 | 
					              break
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # We need to make sure we actually exit, so that the user doesn't get
 | 
				
			||||||
 | 
					    #   stuck with an invisible process.  We want to finalize C modules, so
 | 
				
			||||||
 | 
					    #   we don't use os._exit(), but we don't call sys.exitfunc, which might
 | 
				
			||||||
 | 
					    #   block forever.
 | 
				
			||||||
 | 
					    del sys.exitfunc
 | 
				
			||||||
 | 
					    sys.exit()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					loader()
 | 
				
			||||||
							
								
								
									
										369
									
								
								Lib/idlelib/protocol.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										369
									
								
								Lib/idlelib/protocol.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,369 @@
 | 
				
			||||||
 | 
					"""protocol        (David Scherer <dscherer@cmu.edu>)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     This module implements a simple RPC or "distributed object" protocol.
 | 
				
			||||||
 | 
					     I am probably the 100,000th person to write this in Python, but, hey,
 | 
				
			||||||
 | 
					     it was fun.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     Contents:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       connectionLost is an exception that will be thrown by functions in
 | 
				
			||||||
 | 
					           the protocol module or calls to remote methods that fail because
 | 
				
			||||||
 | 
					           the remote program has closed the socket or because no connection
 | 
				
			||||||
 | 
					           could be established in the first place.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       Server( port=None, connection_hook=None ) creates a server on a
 | 
				
			||||||
 | 
					           well-known port, to which clients can connect.  When a client
 | 
				
			||||||
 | 
					           connects, a Connection is created for it.  If connection_hook
 | 
				
			||||||
 | 
					           is defined, then connection_hook( socket.getpeername() ) is called
 | 
				
			||||||
 | 
					           before a Connection is created, and if it returns false then the
 | 
				
			||||||
 | 
					           connection is refused.  connection_hook must be prepared to be
 | 
				
			||||||
 | 
					           called from any thread.
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					       Client( ip='127.0.0.1', port=None ) returns a Connection to a Server
 | 
				
			||||||
 | 
					           object at a well-known address and port.
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					       Connection( socket ) creates an RPC connection on an arbitrary socket,
 | 
				
			||||||
 | 
					           which must already be connected to another program.  You do not
 | 
				
			||||||
 | 
					           need to use this directly if you are using Client() or Server().
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					       publish( name, connect_function ) provides an object with the
 | 
				
			||||||
 | 
					           specified name to some or all Connections.  When another program
 | 
				
			||||||
 | 
					           calls Connection.getobject() with the specified name, the
 | 
				
			||||||
 | 
					           specified connect_function is called with the arguments
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					              connect_function( conn, addr )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					           where conn is the Connection object to the requesting client and
 | 
				
			||||||
 | 
					           addr is the address returned by socket.getpeername().  If that
 | 
				
			||||||
 | 
					           function returns an object, that object becomes accessible to
 | 
				
			||||||
 | 
					           the caller.  If it returns None, the caller's request fails.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     Connection objects:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       .close() refuses additional RPC messages from the peer, and notifies
 | 
				
			||||||
 | 
					           the peer that the connection has been closed.  All pending remote
 | 
				
			||||||
 | 
					           method calls in either program will fail with a connectionLost
 | 
				
			||||||
 | 
					           exception.  Further remote method calls on this connection will
 | 
				
			||||||
 | 
					           also result in errors.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       .getobject(name) returns a proxy for the remote object with the
 | 
				
			||||||
 | 
					           specified name, if it exists and the peer permits us access.
 | 
				
			||||||
 | 
					           Otherwise, it returns None.  It may throw a connectionLost
 | 
				
			||||||
 | 
					           exception.  The returned proxy supports basic attribute access
 | 
				
			||||||
 | 
					           and method calls, and its methods have an extra attribute,
 | 
				
			||||||
 | 
					           .void, which is a function that has the same effect but always
 | 
				
			||||||
 | 
					           returns None.  This last capability is provided as a performance
 | 
				
			||||||
 | 
					           hack: object.method.void(params) can return without waiting for
 | 
				
			||||||
 | 
					           the remote process to respond, but object.method(params) needs
 | 
				
			||||||
 | 
					           to wait for a return value or exception.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       .rpc_loop(block=0) processes *incoming* messages for this connection.
 | 
				
			||||||
 | 
					           If block=1, it continues processing until an exception or return
 | 
				
			||||||
 | 
					           value is received, which is normally forever.  Otherwise it
 | 
				
			||||||
 | 
					           returns when all currently pending messages have been delivered.
 | 
				
			||||||
 | 
					           It may throw a connectionLost exception.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       .set_close_hook(f) specifies a function to be called when the remote
 | 
				
			||||||
 | 
					           object closes the connection during a call to rpc_loop().  This
 | 
				
			||||||
 | 
					           is a good way for servers to be notified when clients disconnect.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       .set_shutdown_hook(f) specifies a function called *immediately* when
 | 
				
			||||||
 | 
					           the receive loop detects that the connection has been lost.  The
 | 
				
			||||||
 | 
					           provided function must be prepared to run in any thread.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     Server objects:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					       .rpc_loop() processes incoming messages on all connections, and
 | 
				
			||||||
 | 
					           returns when all pending messages have been processed.  It will
 | 
				
			||||||
 | 
					           *not* throw connectionLost exceptions; the
 | 
				
			||||||
 | 
					           Connection.set_close_hook() mechanism is much better for servers.
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import sys, os, string, types
 | 
				
			||||||
 | 
					import socket
 | 
				
			||||||
 | 
					from threading import Thread
 | 
				
			||||||
 | 
					from Queue import Queue, Empty
 | 
				
			||||||
 | 
					from cPickle import Pickler, Unpickler, PicklingError
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class connectionLost:
 | 
				
			||||||
 | 
					    def __init__(self, what=""): self.what = what
 | 
				
			||||||
 | 
					    def __repr__(self): return self.what
 | 
				
			||||||
 | 
					    def __str__(self): return self.what
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def getmethods(cls):
 | 
				
			||||||
 | 
					    "Returns a list of the names of the methods of a class."
 | 
				
			||||||
 | 
					    methods = []
 | 
				
			||||||
 | 
					    for b in cls.__bases__:
 | 
				
			||||||
 | 
					        methods = methods + getmethods(b)
 | 
				
			||||||
 | 
					    d = cls.__dict__
 | 
				
			||||||
 | 
					    for k in d.keys():
 | 
				
			||||||
 | 
					        if type(d[k])==types.FunctionType:
 | 
				
			||||||
 | 
					            methods.append(k)
 | 
				
			||||||
 | 
					    return methods
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class methodproxy:
 | 
				
			||||||
 | 
					    "Proxy for a method of a remote object."
 | 
				
			||||||
 | 
					    def __init__(self, classp, name):
 | 
				
			||||||
 | 
					        self.classp=classp
 | 
				
			||||||
 | 
					        self.name=name
 | 
				
			||||||
 | 
					        self.client = classp.client
 | 
				
			||||||
 | 
					    def __call__(self, *args, **keywords):
 | 
				
			||||||
 | 
					        return self.client.call( 'm', self.classp.name, self.name, args, keywords )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def void(self, *args, **keywords):
 | 
				
			||||||
 | 
					        self.client.call_void( 'm', self.classp.name,self.name,args,keywords)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class classproxy:
 | 
				
			||||||
 | 
					    "Proxy for a remote object."
 | 
				
			||||||
 | 
					    def __init__(self, client, name, methods):
 | 
				
			||||||
 | 
					        self.__dict__['client'] = client
 | 
				
			||||||
 | 
					        self.__dict__['name'] = name
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        for m in methods:
 | 
				
			||||||
 | 
					            prox = methodproxy( self, m )
 | 
				
			||||||
 | 
					            self.__dict__[m] = prox
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __getattr__(self, attr):
 | 
				
			||||||
 | 
					        return self.client.call( 'g', self.name, attr )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __setattr__(self, attr, value):
 | 
				
			||||||
 | 
					        self.client.call_void( 's', self.name, attr, value )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					local_connect  = {}
 | 
				
			||||||
 | 
					def publish(name, connect_function):
 | 
				
			||||||
 | 
					    local_connect[name]=connect_function
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class socketFile:
 | 
				
			||||||
 | 
					    "File emulator based on a socket.  Provides only blocking semantics for now."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, socket):
 | 
				
			||||||
 | 
					        self.socket = socket
 | 
				
			||||||
 | 
					        self.buffer = ''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _recv(self,bytes):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            r=self.socket.recv(bytes)
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            raise connectionLost()
 | 
				
			||||||
 | 
					        if not r:
 | 
				
			||||||
 | 
					            raise connectionLost()
 | 
				
			||||||
 | 
					        return r
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def write(self, string):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.socket.send( string )
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            raise connectionLost()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def read(self,bytes):
 | 
				
			||||||
 | 
					        x = bytes-len(self.buffer)
 | 
				
			||||||
 | 
					        while x>0:
 | 
				
			||||||
 | 
					            self.buffer=self.buffer+self._recv(x)
 | 
				
			||||||
 | 
					            x = bytes-len(self.buffer)
 | 
				
			||||||
 | 
					        s = self.buffer[:bytes]
 | 
				
			||||||
 | 
					        self.buffer=self.buffer[bytes:]
 | 
				
			||||||
 | 
					        return s
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def readline(self):
 | 
				
			||||||
 | 
					        while 1:
 | 
				
			||||||
 | 
					            f = string.find(self.buffer,'\n')
 | 
				
			||||||
 | 
					            if f>=0:
 | 
				
			||||||
 | 
					                s = self.buffer[:f+1]
 | 
				
			||||||
 | 
					                self.buffer=self.buffer[f+1:]
 | 
				
			||||||
 | 
					                return s
 | 
				
			||||||
 | 
					            self.buffer = self.buffer + self._recv(1024)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Connection (Thread):
 | 
				
			||||||
 | 
					    debug = 0
 | 
				
			||||||
 | 
					    def __init__(self, socket):
 | 
				
			||||||
 | 
					        self.local_objects = {}
 | 
				
			||||||
 | 
					        self.socket = socket
 | 
				
			||||||
 | 
					        self.name = socket.getpeername()
 | 
				
			||||||
 | 
					        self.socketfile = socketFile(socket)
 | 
				
			||||||
 | 
					        self.queue = Queue(-1)
 | 
				
			||||||
 | 
					        self.refuse_messages = 0
 | 
				
			||||||
 | 
					        self.cmds = { 'm': self.r_meth,
 | 
				
			||||||
 | 
					                      'g': self.r_get,
 | 
				
			||||||
 | 
					                      's': self.r_set,
 | 
				
			||||||
 | 
					                      'o': self.r_geto,
 | 
				
			||||||
 | 
					                      'e': self.r_exc,
 | 
				
			||||||
 | 
					                     #'r' handled by rpc_loop
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Thread.__init__(self)
 | 
				
			||||||
 | 
					        self.setDaemon(1)
 | 
				
			||||||
 | 
					        self.start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getobject(self, name):
 | 
				
			||||||
 | 
					        methods = self.call( 'o', name )
 | 
				
			||||||
 | 
					        if methods is None: return None
 | 
				
			||||||
 | 
					        return classproxy(self, name, methods)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # close_hook is called from rpc_loop(), like a normal remote method
 | 
				
			||||||
 | 
					    #   invocation
 | 
				
			||||||
 | 
					    def set_close_hook(self,hook): self.close_hook = hook
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # shutdown_hook is called directly from the run() thread, and needs
 | 
				
			||||||
 | 
					    #   to be "thread safe"
 | 
				
			||||||
 | 
					    def set_shutdown_hook(self,hook): self.shutdown_hook = hook
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    close_hook = None
 | 
				
			||||||
 | 
					    shutdown_hook = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def close(self):
 | 
				
			||||||
 | 
					        self._shutdown()
 | 
				
			||||||
 | 
					        self.refuse_messages = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def call(self, c, *args):
 | 
				
			||||||
 | 
					        self.send( (c, args, 1 ) )
 | 
				
			||||||
 | 
					        return self.rpc_loop( block = 1 )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def call_void(self, c, *args):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.send( (c, args, 0 ) )
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					    # the following methods handle individual RPC calls:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def r_geto(self, obj):
 | 
				
			||||||
 | 
					        c = local_connect.get(obj)
 | 
				
			||||||
 | 
					        if not c: return None
 | 
				
			||||||
 | 
					        o = c(self, self.name)
 | 
				
			||||||
 | 
					        if not o: return None
 | 
				
			||||||
 | 
					        self.local_objects[obj] = o
 | 
				
			||||||
 | 
					        return getmethods(o.__class__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def r_meth(self, obj, name, args, keywords):
 | 
				
			||||||
 | 
					        return apply( getattr(self.local_objects[obj],name), args, keywords)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def r_get(self, obj, name):       
 | 
				
			||||||
 | 
					        return getattr(self.local_objects[obj],name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def r_set(self, obj, name, value):
 | 
				
			||||||
 | 
					        setattr(self.local_objects[obj],name,value)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def r_exc(self, e, v):
 | 
				
			||||||
 | 
					        raise e, v
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def rpc_exec(self, cmd, arg, ret):
 | 
				
			||||||
 | 
					        if self.refuse_messages: return
 | 
				
			||||||
 | 
					        if self.debug: print cmd,arg,ret
 | 
				
			||||||
 | 
					        if ret:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                r=apply(self.cmds.get(cmd), arg)
 | 
				
			||||||
 | 
					                self.send( ('r', r, 0) )
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    self.send( ('e', sys.exc_info()[:2], 0) )
 | 
				
			||||||
 | 
					                except PicklingError:
 | 
				
			||||||
 | 
					                    self.send( ('e', (TypeError, 'Unpicklable exception.'), 0 ) )
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            # we cannot report exceptions to the caller, so
 | 
				
			||||||
 | 
					            #   we report them in this process.
 | 
				
			||||||
 | 
					            r=apply(self.cmds.get(cmd), arg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # the following methods implement the RPC and message loops:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def rpc_loop(self, block=0):
 | 
				
			||||||
 | 
					        if self.refuse_messages: raise connectionLost('(already closed)')
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            while 1:
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    cmd, arg, ret = self.queue.get( block )
 | 
				
			||||||
 | 
					                except Empty:
 | 
				
			||||||
 | 
					                    return None
 | 
				
			||||||
 | 
					                if cmd=='r': return arg
 | 
				
			||||||
 | 
					                self.rpc_exec(cmd,arg,ret)
 | 
				
			||||||
 | 
					        except connectionLost:
 | 
				
			||||||
 | 
					            if self.close_hook:
 | 
				
			||||||
 | 
					                self.close_hook()
 | 
				
			||||||
 | 
					                self.close_hook = None
 | 
				
			||||||
 | 
					            raise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run(self):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            while 1:
 | 
				
			||||||
 | 
					                data = self.recv()
 | 
				
			||||||
 | 
					                self.queue.put( data )
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            self.queue.put( ('e', sys.exc_info()[:2], 0) )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # The following send raw pickled data to the peer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def send(self, data):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            Pickler(self.socketfile,1).dump( data )
 | 
				
			||||||
 | 
					        except connectionLost:
 | 
				
			||||||
 | 
					            self._shutdown()
 | 
				
			||||||
 | 
					            if self.shutdown_hook: self.shutdown_hook()
 | 
				
			||||||
 | 
					            raise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def recv(self):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            return Unpickler(self.socketfile).load()
 | 
				
			||||||
 | 
					        except connectionLost:
 | 
				
			||||||
 | 
					            self._shutdown()
 | 
				
			||||||
 | 
					            if self.shutdown_hook: self.shutdown_hook()
 | 
				
			||||||
 | 
					            raise
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            raise
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def _shutdown(self):
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.socket.shutdown(1)
 | 
				
			||||||
 | 
					            self.socket.close()
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Server (Thread):
 | 
				
			||||||
 | 
					    default_port = 0x1D1E   # "IDlE"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, port=None, connection_hook=None):
 | 
				
			||||||
 | 
					        self.connections = []
 | 
				
			||||||
 | 
					        self.port = port or self.default_port
 | 
				
			||||||
 | 
					        self.connection_hook = connection_hook
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            self.wellknown = s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 | 
				
			||||||
 | 
					            s.bind('', self.port)
 | 
				
			||||||
 | 
					            s.listen(3)
 | 
				
			||||||
 | 
					        except:
 | 
				
			||||||
 | 
					            raise connectionLost
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Thread.__init__(self)
 | 
				
			||||||
 | 
					        self.setDaemon(1)
 | 
				
			||||||
 | 
					        self.start()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def run(self):
 | 
				
			||||||
 | 
					        s = self.wellknown
 | 
				
			||||||
 | 
					        while 1:
 | 
				
			||||||
 | 
					            conn, addr = s.accept()
 | 
				
			||||||
 | 
					            if self.connection_hook and not self.connection_hook(addr):
 | 
				
			||||||
 | 
					                try:
 | 
				
			||||||
 | 
					                    conn.shutdown(1)
 | 
				
			||||||
 | 
					                except:
 | 
				
			||||||
 | 
					                    pass
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
 | 
					            self.connections.append( Connection(conn) )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def rpc_loop(self):
 | 
				
			||||||
 | 
					        cns = self.connections[:]
 | 
				
			||||||
 | 
					        for c in cns:
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                c.rpc_loop(block = 0)
 | 
				
			||||||
 | 
					            except connectionLost:
 | 
				
			||||||
 | 
					                if c in self.connections:
 | 
				
			||||||
 | 
					                    self.connections.remove(c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def Client(ip='127.0.0.1', port=None):
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 | 
				
			||||||
 | 
					        s.connect(ip,port or Server.default_port)
 | 
				
			||||||
 | 
					    except socket.error, what:
 | 
				
			||||||
 | 
					        raise connectionLost(str(what))
 | 
				
			||||||
 | 
					    except:
 | 
				
			||||||
 | 
					        raise connectionLost()
 | 
				
			||||||
 | 
					    return Connection(s)
 | 
				
			||||||
							
								
								
									
										336
									
								
								Lib/idlelib/pyclbr.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										336
									
								
								Lib/idlelib/pyclbr.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,336 @@
 | 
				
			||||||
 | 
					"""Parse a Python file and retrieve classes and methods.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Parse enough of a Python file to recognize class and method
 | 
				
			||||||
 | 
					definitions and to find out the superclasses of a class.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The interface consists of a single function:
 | 
				
			||||||
 | 
						readmodule(module, path)
 | 
				
			||||||
 | 
					module is the name of a Python module, path is an optional list of
 | 
				
			||||||
 | 
					directories where the module is to be searched.  If present, path is
 | 
				
			||||||
 | 
					prepended to the system search path sys.path.
 | 
				
			||||||
 | 
					The return value is a dictionary.  The keys of the dictionary are
 | 
				
			||||||
 | 
					the names of the classes defined in the module (including classes
 | 
				
			||||||
 | 
					that are defined via the from XXX import YYY construct).  The values
 | 
				
			||||||
 | 
					are class instances of the class Class defined here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A class is described by the class Class in this module.  Instances
 | 
				
			||||||
 | 
					of this class have the following instance variables:
 | 
				
			||||||
 | 
						name -- the name of the class
 | 
				
			||||||
 | 
						super -- a list of super classes (Class instances)
 | 
				
			||||||
 | 
						methods -- a dictionary of methods
 | 
				
			||||||
 | 
						file -- the file in which the class was defined
 | 
				
			||||||
 | 
						lineno -- the line in the file on which the class statement occurred
 | 
				
			||||||
 | 
					The dictionary of methods uses the method names as keys and the line
 | 
				
			||||||
 | 
					numbers on which the method was defined as values.
 | 
				
			||||||
 | 
					If the name of a super class is not recognized, the corresponding
 | 
				
			||||||
 | 
					entry in the list of super classes is not a class instance but a
 | 
				
			||||||
 | 
					string giving the name of the super class.  Since import statements
 | 
				
			||||||
 | 
					are recognized and imported modules are scanned as well, this
 | 
				
			||||||
 | 
					shouldn't happen often.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BUGS
 | 
				
			||||||
 | 
					- Continuation lines are not dealt with at all.
 | 
				
			||||||
 | 
					- While triple-quoted strings won't confuse it, lines that look like
 | 
				
			||||||
 | 
					  def, class, import or "from ... import" stmts inside backslash-continued
 | 
				
			||||||
 | 
					  single-quoted strings are treated like code.  The expense of stopping
 | 
				
			||||||
 | 
					  that isn't worth it.
 | 
				
			||||||
 | 
					- Code that doesn't pass tabnanny or python -t will confuse it, unless
 | 
				
			||||||
 | 
					  you set the module TABWIDTH vrbl (default 8) to the correct tab width
 | 
				
			||||||
 | 
					  for the file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PACKAGE RELATED BUGS
 | 
				
			||||||
 | 
					- If you have a package and a module inside that or another package
 | 
				
			||||||
 | 
					  with the same name, module caching doesn't work properly since the
 | 
				
			||||||
 | 
					  key is the base name of the module/package.
 | 
				
			||||||
 | 
					- The only entry that is returned when you readmodule a package is a
 | 
				
			||||||
 | 
					  __path__ whose value is a list which confuses certain class browsers.
 | 
				
			||||||
 | 
					- When code does:
 | 
				
			||||||
 | 
					  from package import subpackage
 | 
				
			||||||
 | 
					  class MyClass(subpackage.SuperClass):
 | 
				
			||||||
 | 
					    ...
 | 
				
			||||||
 | 
					  It can't locate the parent.  It probably needs to have the same
 | 
				
			||||||
 | 
					  hairy logic that the import locator already does.  (This logic
 | 
				
			||||||
 | 
					  exists coded in Python in the freeze package.)
 | 
				
			||||||
 | 
					"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import imp
 | 
				
			||||||
 | 
					import re
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TABWIDTH = 8
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_getnext = re.compile(r"""
 | 
				
			||||||
 | 
					    (?P<String>
 | 
				
			||||||
 | 
					       \""" [^"\\]* (?:
 | 
				
			||||||
 | 
								(?: \\. | "(?!"") )
 | 
				
			||||||
 | 
								[^"\\]*
 | 
				
			||||||
 | 
							    )*
 | 
				
			||||||
 | 
					       \"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    |   ''' [^'\\]* (?:
 | 
				
			||||||
 | 
								(?: \\. | '(?!'') )
 | 
				
			||||||
 | 
								[^'\\]*
 | 
				
			||||||
 | 
							    )*
 | 
				
			||||||
 | 
						'''
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					|   (?P<Method>
 | 
				
			||||||
 | 
						^
 | 
				
			||||||
 | 
						(?P<MethodIndent> [ \t]* )
 | 
				
			||||||
 | 
						def [ \t]+
 | 
				
			||||||
 | 
						(?P<MethodName> [a-zA-Z_] \w* )
 | 
				
			||||||
 | 
						[ \t]* \(
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					|   (?P<Class>
 | 
				
			||||||
 | 
						^
 | 
				
			||||||
 | 
						(?P<ClassIndent> [ \t]* )
 | 
				
			||||||
 | 
						class [ \t]+
 | 
				
			||||||
 | 
						(?P<ClassName> [a-zA-Z_] \w* )
 | 
				
			||||||
 | 
						[ \t]*
 | 
				
			||||||
 | 
						(?P<ClassSupers> \( [^)\n]* \) )?
 | 
				
			||||||
 | 
						[ \t]* :
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					|   (?P<Import>
 | 
				
			||||||
 | 
						^ import [ \t]+
 | 
				
			||||||
 | 
						(?P<ImportList> [^#;\n]+ )
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					|   (?P<ImportFrom>
 | 
				
			||||||
 | 
						^ from [ \t]+
 | 
				
			||||||
 | 
						(?P<ImportFromPath>
 | 
				
			||||||
 | 
						    [a-zA-Z_] \w*
 | 
				
			||||||
 | 
						    (?:
 | 
				
			||||||
 | 
							[ \t]* \. [ \t]* [a-zA-Z_] \w*
 | 
				
			||||||
 | 
						    )*
 | 
				
			||||||
 | 
						)
 | 
				
			||||||
 | 
						[ \t]+
 | 
				
			||||||
 | 
						import [ \t]+
 | 
				
			||||||
 | 
						(?P<ImportFromList> [^#;\n]+ )
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					""", re.VERBOSE | re.DOTALL | re.MULTILINE).search
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					_modules = {}                           # cache of modules we've seen
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# each Python class is represented by an instance of this class
 | 
				
			||||||
 | 
					class Class:
 | 
				
			||||||
 | 
						'''Class to represent a Python class.'''
 | 
				
			||||||
 | 
						def __init__(self, module, name, super, file, lineno):
 | 
				
			||||||
 | 
							self.module = module
 | 
				
			||||||
 | 
							self.name = name
 | 
				
			||||||
 | 
							if super is None:
 | 
				
			||||||
 | 
								super = []
 | 
				
			||||||
 | 
							self.super = super
 | 
				
			||||||
 | 
							self.methods = {}
 | 
				
			||||||
 | 
							self.file = file
 | 
				
			||||||
 | 
							self.lineno = lineno
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						def _addmethod(self, name, lineno):
 | 
				
			||||||
 | 
							self.methods[name] = lineno
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Function(Class):
 | 
				
			||||||
 | 
						'''Class to represent a top-level Python function'''
 | 
				
			||||||
 | 
						def __init__(self, module, name, file, lineno):
 | 
				
			||||||
 | 
							Class.__init__(self, module, name, None, file, lineno)
 | 
				
			||||||
 | 
						def _addmethod(self, name, lineno):
 | 
				
			||||||
 | 
							assert 0, "Function._addmethod() shouldn't be called"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def readmodule(module, path=[], inpackage=0):
 | 
				
			||||||
 | 
						'''Backwards compatible interface.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Like readmodule_ex() but strips Function objects from the
 | 
				
			||||||
 | 
						resulting dictionary.'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dict = readmodule_ex(module, path, inpackage)
 | 
				
			||||||
 | 
						res = {}
 | 
				
			||||||
 | 
						for key, value in dict.items():
 | 
				
			||||||
 | 
							if not isinstance(value, Function):
 | 
				
			||||||
 | 
								res[key] = value
 | 
				
			||||||
 | 
						return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def readmodule_ex(module, path=[], inpackage=0):
 | 
				
			||||||
 | 
						'''Read a module file and return a dictionary of classes.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						Search for MODULE in PATH and sys.path, read and parse the
 | 
				
			||||||
 | 
						module and return a dictionary with one entry for each class
 | 
				
			||||||
 | 
						found in the module.'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dict = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						i = string.rfind(module, '.')
 | 
				
			||||||
 | 
						if i >= 0:
 | 
				
			||||||
 | 
							# Dotted module name
 | 
				
			||||||
 | 
							package = string.strip(module[:i])
 | 
				
			||||||
 | 
							submodule = string.strip(module[i+1:])
 | 
				
			||||||
 | 
							parent = readmodule(package, path, inpackage)
 | 
				
			||||||
 | 
							child = readmodule(submodule, parent['__path__'], 1)
 | 
				
			||||||
 | 
							return child
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if _modules.has_key(module):
 | 
				
			||||||
 | 
							# we've seen this module before...
 | 
				
			||||||
 | 
							return _modules[module]
 | 
				
			||||||
 | 
						if module in sys.builtin_module_names:
 | 
				
			||||||
 | 
							# this is a built-in module
 | 
				
			||||||
 | 
							_modules[module] = dict
 | 
				
			||||||
 | 
							return dict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# search the path for the module
 | 
				
			||||||
 | 
						f = None
 | 
				
			||||||
 | 
						if inpackage:
 | 
				
			||||||
 | 
							try:
 | 
				
			||||||
 | 
								f, file, (suff, mode, type) = \
 | 
				
			||||||
 | 
									imp.find_module(module, path)
 | 
				
			||||||
 | 
							except ImportError:
 | 
				
			||||||
 | 
								f = None
 | 
				
			||||||
 | 
						if f is None:
 | 
				
			||||||
 | 
							fullpath = list(path) + sys.path
 | 
				
			||||||
 | 
							f, file, (suff, mode, type) = imp.find_module(module, fullpath)
 | 
				
			||||||
 | 
						if type == imp.PKG_DIRECTORY:
 | 
				
			||||||
 | 
							dict['__path__'] = [file]
 | 
				
			||||||
 | 
							_modules[module] = dict
 | 
				
			||||||
 | 
							path = [file] + path
 | 
				
			||||||
 | 
							f, file, (suff, mode, type) = \
 | 
				
			||||||
 | 
									imp.find_module('__init__', [file])
 | 
				
			||||||
 | 
						if type != imp.PY_SOURCE:
 | 
				
			||||||
 | 
							# not Python source, can't do anything with this module
 | 
				
			||||||
 | 
							f.close()
 | 
				
			||||||
 | 
							_modules[module] = dict
 | 
				
			||||||
 | 
							return dict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_modules[module] = dict
 | 
				
			||||||
 | 
						imports = []
 | 
				
			||||||
 | 
						classstack = []	# stack of (class, indent) pairs
 | 
				
			||||||
 | 
						src = f.read()
 | 
				
			||||||
 | 
						f.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						# To avoid having to stop the regexp at each newline, instead
 | 
				
			||||||
 | 
						# when we need a line number we simply string.count the number of
 | 
				
			||||||
 | 
						# newlines in the string since the last time we did this; i.e.,
 | 
				
			||||||
 | 
						#    lineno = lineno + \
 | 
				
			||||||
 | 
						#             string.count(src, '\n', last_lineno_pos, here)
 | 
				
			||||||
 | 
						#    last_lineno_pos = here
 | 
				
			||||||
 | 
						countnl = string.count
 | 
				
			||||||
 | 
						lineno, last_lineno_pos = 1, 0
 | 
				
			||||||
 | 
						i = 0
 | 
				
			||||||
 | 
						while 1:
 | 
				
			||||||
 | 
							m = _getnext(src, i)
 | 
				
			||||||
 | 
							if not m:
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							start, i = m.span()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if m.start("Method") >= 0:
 | 
				
			||||||
 | 
								# found a method definition or function
 | 
				
			||||||
 | 
								thisindent = _indent(m.group("MethodIndent"))
 | 
				
			||||||
 | 
								meth_name = m.group("MethodName")
 | 
				
			||||||
 | 
								lineno = lineno + \
 | 
				
			||||||
 | 
									 countnl(src, '\n',
 | 
				
			||||||
 | 
										 last_lineno_pos, start)
 | 
				
			||||||
 | 
								last_lineno_pos = start
 | 
				
			||||||
 | 
								# close all classes indented at least as much
 | 
				
			||||||
 | 
								while classstack and \
 | 
				
			||||||
 | 
								      classstack[-1][1] >= thisindent:
 | 
				
			||||||
 | 
									del classstack[-1]
 | 
				
			||||||
 | 
								if classstack:
 | 
				
			||||||
 | 
									# it's a class method
 | 
				
			||||||
 | 
									cur_class = classstack[-1][0]
 | 
				
			||||||
 | 
									cur_class._addmethod(meth_name, lineno)
 | 
				
			||||||
 | 
								else:
 | 
				
			||||||
 | 
									# it's a function
 | 
				
			||||||
 | 
									f = Function(module, meth_name,
 | 
				
			||||||
 | 
										     file, lineno)
 | 
				
			||||||
 | 
									dict[meth_name] = f
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							elif m.start("String") >= 0:
 | 
				
			||||||
 | 
								pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							elif m.start("Class") >= 0:
 | 
				
			||||||
 | 
								# we found a class definition
 | 
				
			||||||
 | 
								thisindent = _indent(m.group("ClassIndent"))
 | 
				
			||||||
 | 
								# close all classes indented at least as much
 | 
				
			||||||
 | 
								while classstack and \
 | 
				
			||||||
 | 
								      classstack[-1][1] >= thisindent:
 | 
				
			||||||
 | 
									del classstack[-1]
 | 
				
			||||||
 | 
								lineno = lineno + \
 | 
				
			||||||
 | 
									 countnl(src, '\n', last_lineno_pos, start)
 | 
				
			||||||
 | 
								last_lineno_pos = start
 | 
				
			||||||
 | 
								class_name = m.group("ClassName")
 | 
				
			||||||
 | 
								inherit = m.group("ClassSupers")
 | 
				
			||||||
 | 
								if inherit:
 | 
				
			||||||
 | 
									# the class inherits from other classes
 | 
				
			||||||
 | 
									inherit = string.strip(inherit[1:-1])
 | 
				
			||||||
 | 
									names = []
 | 
				
			||||||
 | 
									for n in string.splitfields(inherit, ','):
 | 
				
			||||||
 | 
										n = string.strip(n)
 | 
				
			||||||
 | 
										if dict.has_key(n):
 | 
				
			||||||
 | 
											# we know this super class
 | 
				
			||||||
 | 
											n = dict[n]
 | 
				
			||||||
 | 
										else:
 | 
				
			||||||
 | 
											c = string.splitfields(n, '.')
 | 
				
			||||||
 | 
											if len(c) > 1:
 | 
				
			||||||
 | 
												# super class
 | 
				
			||||||
 | 
												# is of the
 | 
				
			||||||
 | 
												# form module.class:
 | 
				
			||||||
 | 
												# look in
 | 
				
			||||||
 | 
												# module for class
 | 
				
			||||||
 | 
												m = c[-2]
 | 
				
			||||||
 | 
												c = c[-1]
 | 
				
			||||||
 | 
												if _modules.has_key(m):
 | 
				
			||||||
 | 
													d = _modules[m]
 | 
				
			||||||
 | 
													if d.has_key(c):
 | 
				
			||||||
 | 
														n = d[c]
 | 
				
			||||||
 | 
										names.append(n)
 | 
				
			||||||
 | 
									inherit = names
 | 
				
			||||||
 | 
								# remember this class
 | 
				
			||||||
 | 
								cur_class = Class(module, class_name, inherit,
 | 
				
			||||||
 | 
										  file, lineno)
 | 
				
			||||||
 | 
								dict[class_name] = cur_class
 | 
				
			||||||
 | 
								classstack.append((cur_class, thisindent))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							elif m.start("Import") >= 0:
 | 
				
			||||||
 | 
								# import module
 | 
				
			||||||
 | 
								for n in string.split(m.group("ImportList"), ','):
 | 
				
			||||||
 | 
									n = string.strip(n)
 | 
				
			||||||
 | 
									try:
 | 
				
			||||||
 | 
										# recursively read the imported module
 | 
				
			||||||
 | 
										d = readmodule(n, path, inpackage)
 | 
				
			||||||
 | 
									except:
 | 
				
			||||||
 | 
										##print 'module', n, 'not found'
 | 
				
			||||||
 | 
										pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							elif m.start("ImportFrom") >= 0:
 | 
				
			||||||
 | 
								# from module import stuff
 | 
				
			||||||
 | 
								mod = m.group("ImportFromPath")
 | 
				
			||||||
 | 
								names = string.split(m.group("ImportFromList"), ',')
 | 
				
			||||||
 | 
								try:
 | 
				
			||||||
 | 
									# recursively read the imported module
 | 
				
			||||||
 | 
									d = readmodule(mod, path, inpackage)
 | 
				
			||||||
 | 
								except:
 | 
				
			||||||
 | 
									##print 'module', mod, 'not found'
 | 
				
			||||||
 | 
									continue
 | 
				
			||||||
 | 
								# add any classes that were defined in the
 | 
				
			||||||
 | 
								# imported module to our name space if they
 | 
				
			||||||
 | 
								# were mentioned in the list
 | 
				
			||||||
 | 
								for n in names:
 | 
				
			||||||
 | 
									n = string.strip(n)
 | 
				
			||||||
 | 
									if d.has_key(n):
 | 
				
			||||||
 | 
										dict[n] = d[n]
 | 
				
			||||||
 | 
									elif n == '*':
 | 
				
			||||||
 | 
										# only add a name if not
 | 
				
			||||||
 | 
										# already there (to mimic what
 | 
				
			||||||
 | 
										# Python does internally)
 | 
				
			||||||
 | 
										# also don't add names that
 | 
				
			||||||
 | 
										# start with _
 | 
				
			||||||
 | 
										for n in d.keys():
 | 
				
			||||||
 | 
											if n[0] != '_' and \
 | 
				
			||||||
 | 
											   not dict.has_key(n):
 | 
				
			||||||
 | 
												dict[n] = d[n]
 | 
				
			||||||
 | 
							else:
 | 
				
			||||||
 | 
								assert 0, "regexp _getnext found something unexpected"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return dict
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def _indent(ws, _expandtabs=string.expandtabs):
 | 
				
			||||||
 | 
						return len(_expandtabs(ws, TABWIDTH))
 | 
				
			||||||
							
								
								
									
										59
									
								
								Lib/idlelib/spawn.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								Lib/idlelib/spawn.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,59 @@
 | 
				
			||||||
 | 
					# spawn - This is ugly, OS-specific code to spawn a separate process.  It
 | 
				
			||||||
 | 
					#         also defines a function for getting the version of a path most
 | 
				
			||||||
 | 
					#         likely to work with cranky API functions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def hardpath(path):
 | 
				
			||||||
 | 
					    path = os.path.normcase(os.path.abspath(path))
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        import win32api
 | 
				
			||||||
 | 
					        path = win32api.GetShortPathName( path )
 | 
				
			||||||
 | 
					    except:
 | 
				
			||||||
 | 
					        pass
 | 
				
			||||||
 | 
					    return path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if hasattr(os, 'spawnv'):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # Windows-ish OS: we use spawnv(), and stick quotes around arguments
 | 
				
			||||||
 | 
					  #   in case they contains spaces, since Windows will jam all the
 | 
				
			||||||
 | 
					  #   arguments to spawn() or exec() together into one string.  The
 | 
				
			||||||
 | 
					  #   kill_zombies function is a noop.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def spawn(bin, *args):
 | 
				
			||||||
 | 
					    nargs = [bin]
 | 
				
			||||||
 | 
					    for arg in args:
 | 
				
			||||||
 | 
					      nargs.append( '"'+arg+'"' )
 | 
				
			||||||
 | 
					    os.spawnv( os.P_NOWAIT, bin, nargs )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def kill_zombies(): pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					elif hasattr(os, 'fork'):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  # UNIX-ish operating system: we fork() and exec(), and we have to track
 | 
				
			||||||
 | 
					  #   the pids of our children and call waitpid() on them to avoid leaving
 | 
				
			||||||
 | 
					  #   zombies in the process table.  kill_zombies() does the dirty work, and
 | 
				
			||||||
 | 
					  #   should be called periodically.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  zombies = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def spawn(bin, *args):
 | 
				
			||||||
 | 
					    pid = os.fork()
 | 
				
			||||||
 | 
					    if pid:
 | 
				
			||||||
 | 
					      zombies.append(pid)
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					      os.execv( bin, (bin, ) + args )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def kill_zombies():
 | 
				
			||||||
 | 
					      for z in zombies[:]:
 | 
				
			||||||
 | 
					          stat = os.waitpid(z, os.WNOHANG)
 | 
				
			||||||
 | 
					          if stat[0]==z:
 | 
				
			||||||
 | 
					              zombies.remove(z)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					else:
 | 
				
			||||||
 | 
					  # If you get here, you may be able to write an alternative implementation
 | 
				
			||||||
 | 
					  # of these functions for your OS.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def kill_zombies(): pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  raise OSError, 'This OS does not support fork() or spawnv().'
 | 
				
			||||||
							
								
								
									
										372
									
								
								Lib/idlelib/tabnanny.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										372
									
								
								Lib/idlelib/tabnanny.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,372 @@
 | 
				
			||||||
 | 
					#! /usr/bin/env python
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					"""The Tab Nanny despises ambiguous indentation.  She knows no mercy."""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Released to the public domain, by Tim Peters, 15 April 1998.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# XXX Note: this is now a standard library module.
 | 
				
			||||||
 | 
					# XXX The API needs to undergo changes however; the current code is too
 | 
				
			||||||
 | 
					# XXX script-like.  This will be addressed later.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					__version__ = "6"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import os
 | 
				
			||||||
 | 
					import sys
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					import getopt
 | 
				
			||||||
 | 
					import tokenize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					verbose = 0
 | 
				
			||||||
 | 
					filename_only = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def errprint(*args):
 | 
				
			||||||
 | 
					    sep = ""
 | 
				
			||||||
 | 
					    for arg in args:
 | 
				
			||||||
 | 
					        sys.stderr.write(sep + str(arg))
 | 
				
			||||||
 | 
					        sep = " "
 | 
				
			||||||
 | 
					    sys.stderr.write("\n")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    global verbose, filename_only
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        opts, args = getopt.getopt(sys.argv[1:], "qv")
 | 
				
			||||||
 | 
					    except getopt.error, msg:
 | 
				
			||||||
 | 
					        errprint(msg)
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					    for o, a in opts:
 | 
				
			||||||
 | 
					        if o == '-q':
 | 
				
			||||||
 | 
					            filename_only = filename_only + 1
 | 
				
			||||||
 | 
					        if o == '-v':
 | 
				
			||||||
 | 
					            verbose = verbose + 1
 | 
				
			||||||
 | 
					    if not args:
 | 
				
			||||||
 | 
					        errprint("Usage:", sys.argv[0], "[-v] file_or_directory ...")
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					    for arg in args:
 | 
				
			||||||
 | 
					        check(arg)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NannyNag:
 | 
				
			||||||
 | 
					    def __init__(self, lineno, msg, line):
 | 
				
			||||||
 | 
					        self.lineno, self.msg, self.line = lineno, msg, line
 | 
				
			||||||
 | 
					    def get_lineno(self):
 | 
				
			||||||
 | 
					        return self.lineno
 | 
				
			||||||
 | 
					    def get_msg(self):
 | 
				
			||||||
 | 
					        return self.msg
 | 
				
			||||||
 | 
					    def get_line(self):
 | 
				
			||||||
 | 
					        return self.line
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def check(file):
 | 
				
			||||||
 | 
					    if os.path.isdir(file) and not os.path.islink(file):
 | 
				
			||||||
 | 
					        if verbose:
 | 
				
			||||||
 | 
					            print "%s: listing directory" % `file`
 | 
				
			||||||
 | 
					        names = os.listdir(file)
 | 
				
			||||||
 | 
					        for name in names:
 | 
				
			||||||
 | 
					            fullname = os.path.join(file, name)
 | 
				
			||||||
 | 
					            if (os.path.isdir(fullname) and
 | 
				
			||||||
 | 
					                not os.path.islink(fullname) or
 | 
				
			||||||
 | 
					                os.path.normcase(name[-3:]) == ".py"):
 | 
				
			||||||
 | 
					                check(fullname)
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        f = open(file)
 | 
				
			||||||
 | 
					    except IOError, msg:
 | 
				
			||||||
 | 
					        errprint("%s: I/O Error: %s" % (`file`, str(msg)))
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if verbose > 1:
 | 
				
			||||||
 | 
					        print "checking", `file`, "..."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    reset_globals()
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        tokenize.tokenize(f.readline, tokeneater)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    except tokenize.TokenError, msg:
 | 
				
			||||||
 | 
					        errprint("%s: Token Error: %s" % (`file`, str(msg)))
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    except NannyNag, nag:
 | 
				
			||||||
 | 
					        badline = nag.get_lineno()
 | 
				
			||||||
 | 
					        line = nag.get_line()
 | 
				
			||||||
 | 
					        if verbose:
 | 
				
			||||||
 | 
					            print "%s: *** Line %d: trouble in tab city! ***" % (
 | 
				
			||||||
 | 
					                `file`, badline)
 | 
				
			||||||
 | 
					            print "offending line:", `line`
 | 
				
			||||||
 | 
					            print nag.get_msg()
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if ' ' in file: file = '"' + file + '"'
 | 
				
			||||||
 | 
					            if filename_only: print file
 | 
				
			||||||
 | 
					            else: print file, badline, `line`
 | 
				
			||||||
 | 
					        return
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if verbose:
 | 
				
			||||||
 | 
					        print "%s: Clean bill of health." % `file`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Whitespace:
 | 
				
			||||||
 | 
					    # the characters used for space and tab
 | 
				
			||||||
 | 
					    S, T = ' \t'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # members:
 | 
				
			||||||
 | 
					    #   raw
 | 
				
			||||||
 | 
					    #       the original string
 | 
				
			||||||
 | 
					    #   n
 | 
				
			||||||
 | 
					    #       the number of leading whitespace characters in raw
 | 
				
			||||||
 | 
					    #   nt
 | 
				
			||||||
 | 
					    #       the number of tabs in raw[:n]
 | 
				
			||||||
 | 
					    #   norm
 | 
				
			||||||
 | 
					    #       the normal form as a pair (count, trailing), where:
 | 
				
			||||||
 | 
					    #       count
 | 
				
			||||||
 | 
					    #           a tuple such that raw[:n] contains count[i]
 | 
				
			||||||
 | 
					    #           instances of S * i + T
 | 
				
			||||||
 | 
					    #       trailing
 | 
				
			||||||
 | 
					    #           the number of trailing spaces in raw[:n]
 | 
				
			||||||
 | 
					    #       It's A Theorem that m.indent_level(t) ==
 | 
				
			||||||
 | 
					    #       n.indent_level(t) for all t >= 1 iff m.norm == n.norm.
 | 
				
			||||||
 | 
					    #   is_simple
 | 
				
			||||||
 | 
					    #       true iff raw[:n] is of the form (T*)(S*)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def __init__(self, ws):
 | 
				
			||||||
 | 
					        self.raw  = ws
 | 
				
			||||||
 | 
					        S, T = Whitespace.S, Whitespace.T
 | 
				
			||||||
 | 
					        count = []
 | 
				
			||||||
 | 
					        b = n = nt = 0
 | 
				
			||||||
 | 
					        for ch in self.raw:
 | 
				
			||||||
 | 
					            if ch == S:
 | 
				
			||||||
 | 
					                n = n + 1
 | 
				
			||||||
 | 
					                b = b + 1
 | 
				
			||||||
 | 
					            elif ch == T:
 | 
				
			||||||
 | 
					                n = n + 1
 | 
				
			||||||
 | 
					                nt = nt + 1
 | 
				
			||||||
 | 
					                if b >= len(count):
 | 
				
			||||||
 | 
					                    count = count + [0] * (b - len(count) + 1)
 | 
				
			||||||
 | 
					                count[b] = count[b] + 1
 | 
				
			||||||
 | 
					                b = 0
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                break
 | 
				
			||||||
 | 
					        self.n    = n
 | 
				
			||||||
 | 
					        self.nt   = nt
 | 
				
			||||||
 | 
					        self.norm = tuple(count), b
 | 
				
			||||||
 | 
					        self.is_simple = len(count) <= 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # return length of longest contiguous run of spaces (whether or not
 | 
				
			||||||
 | 
					    # preceding a tab)
 | 
				
			||||||
 | 
					    def longest_run_of_spaces(self):
 | 
				
			||||||
 | 
					        count, trailing = self.norm
 | 
				
			||||||
 | 
					        return max(len(count)-1, trailing)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def indent_level(self, tabsize):
 | 
				
			||||||
 | 
					        # count, il = self.norm
 | 
				
			||||||
 | 
					        # for i in range(len(count)):
 | 
				
			||||||
 | 
					        #    if count[i]:
 | 
				
			||||||
 | 
					        #        il = il + (i/tabsize + 1)*tabsize * count[i]
 | 
				
			||||||
 | 
					        # return il
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # quicker:
 | 
				
			||||||
 | 
					        # il = trailing + sum (i/ts + 1)*ts*count[i] =
 | 
				
			||||||
 | 
					        # trailing + ts * sum (i/ts + 1)*count[i] =
 | 
				
			||||||
 | 
					        # trailing + ts * sum i/ts*count[i] + count[i] =
 | 
				
			||||||
 | 
					        # trailing + ts * [(sum i/ts*count[i]) + (sum count[i])] =
 | 
				
			||||||
 | 
					        # trailing + ts * [(sum i/ts*count[i]) + num_tabs]
 | 
				
			||||||
 | 
					        # and note that i/ts*count[i] is 0 when i < ts
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        count, trailing = self.norm
 | 
				
			||||||
 | 
					        il = 0
 | 
				
			||||||
 | 
					        for i in range(tabsize, len(count)):
 | 
				
			||||||
 | 
					            il = il + i/tabsize * count[i]
 | 
				
			||||||
 | 
					        return trailing + tabsize * (il + self.nt)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # return true iff self.indent_level(t) == other.indent_level(t)
 | 
				
			||||||
 | 
					    # for all t >= 1
 | 
				
			||||||
 | 
					    def equal(self, other):
 | 
				
			||||||
 | 
					        return self.norm == other.norm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # return a list of tuples (ts, i1, i2) such that
 | 
				
			||||||
 | 
					    # i1 == self.indent_level(ts) != other.indent_level(ts) == i2.
 | 
				
			||||||
 | 
					    # Intended to be used after not self.equal(other) is known, in which
 | 
				
			||||||
 | 
					    # case it will return at least one witnessing tab size.
 | 
				
			||||||
 | 
					    def not_equal_witness(self, other):
 | 
				
			||||||
 | 
					        n = max(self.longest_run_of_spaces(),
 | 
				
			||||||
 | 
					                other.longest_run_of_spaces()) + 1
 | 
				
			||||||
 | 
					        a = []
 | 
				
			||||||
 | 
					        for ts in range(1, n+1):
 | 
				
			||||||
 | 
					            if self.indent_level(ts) != other.indent_level(ts):
 | 
				
			||||||
 | 
					                a.append( (ts,
 | 
				
			||||||
 | 
					                           self.indent_level(ts),
 | 
				
			||||||
 | 
					                           other.indent_level(ts)) )
 | 
				
			||||||
 | 
					        return a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Return true iff self.indent_level(t) < other.indent_level(t)
 | 
				
			||||||
 | 
					    # for all t >= 1.
 | 
				
			||||||
 | 
					    # The algorithm is due to Vincent Broman.
 | 
				
			||||||
 | 
					    # Easy to prove it's correct.
 | 
				
			||||||
 | 
					    # XXXpost that.
 | 
				
			||||||
 | 
					    # Trivial to prove n is sharp (consider T vs ST).
 | 
				
			||||||
 | 
					    # Unknown whether there's a faster general way.  I suspected so at
 | 
				
			||||||
 | 
					    # first, but no longer.
 | 
				
			||||||
 | 
					    # For the special (but common!) case where M and N are both of the
 | 
				
			||||||
 | 
					    # form (T*)(S*), M.less(N) iff M.len() < N.len() and
 | 
				
			||||||
 | 
					    # M.num_tabs() <= N.num_tabs(). Proof is easy but kinda long-winded.
 | 
				
			||||||
 | 
					    # XXXwrite that up.
 | 
				
			||||||
 | 
					    # Note that M is of the form (T*)(S*) iff len(M.norm[0]) <= 1.
 | 
				
			||||||
 | 
					    def less(self, other):
 | 
				
			||||||
 | 
					        if self.n >= other.n:
 | 
				
			||||||
 | 
					            return 0
 | 
				
			||||||
 | 
					        if self.is_simple and other.is_simple:
 | 
				
			||||||
 | 
					            return self.nt <= other.nt
 | 
				
			||||||
 | 
					        n = max(self.longest_run_of_spaces(),
 | 
				
			||||||
 | 
					                other.longest_run_of_spaces()) + 1
 | 
				
			||||||
 | 
					        # the self.n >= other.n test already did it for ts=1
 | 
				
			||||||
 | 
					        for ts in range(2, n+1):
 | 
				
			||||||
 | 
					            if self.indent_level(ts) >= other.indent_level(ts):
 | 
				
			||||||
 | 
					                return 0
 | 
				
			||||||
 | 
					        return 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # return a list of tuples (ts, i1, i2) such that
 | 
				
			||||||
 | 
					    # i1 == self.indent_level(ts) >= other.indent_level(ts) == i2.
 | 
				
			||||||
 | 
					    # Intended to be used after not self.less(other) is known, in which
 | 
				
			||||||
 | 
					    # case it will return at least one witnessing tab size.
 | 
				
			||||||
 | 
					    def not_less_witness(self, other):
 | 
				
			||||||
 | 
					        n = max(self.longest_run_of_spaces(),
 | 
				
			||||||
 | 
					                other.longest_run_of_spaces()) + 1
 | 
				
			||||||
 | 
					        a = []
 | 
				
			||||||
 | 
					        for ts in range(1, n+1):
 | 
				
			||||||
 | 
					            if self.indent_level(ts) >= other.indent_level(ts):
 | 
				
			||||||
 | 
					                a.append( (ts,
 | 
				
			||||||
 | 
					                           self.indent_level(ts),
 | 
				
			||||||
 | 
					                           other.indent_level(ts)) )
 | 
				
			||||||
 | 
					        return a
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def format_witnesses(w):
 | 
				
			||||||
 | 
					    import string
 | 
				
			||||||
 | 
					    firsts = map(lambda tup: str(tup[0]), w)
 | 
				
			||||||
 | 
					    prefix = "at tab size"
 | 
				
			||||||
 | 
					    if len(w) > 1:
 | 
				
			||||||
 | 
					        prefix = prefix + "s"
 | 
				
			||||||
 | 
					    return prefix + " " + string.join(firsts, ', ')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# The collection of globals, the reset_globals() function, and the
 | 
				
			||||||
 | 
					# tokeneater() function, depend on which version of tokenize is
 | 
				
			||||||
 | 
					# in use.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if hasattr(tokenize, 'NL'):
 | 
				
			||||||
 | 
					 # take advantage of Guido's patch!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 indents = []
 | 
				
			||||||
 | 
					 check_equal = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 def reset_globals():
 | 
				
			||||||
 | 
					     global indents, check_equal
 | 
				
			||||||
 | 
					     check_equal = 0
 | 
				
			||||||
 | 
					     indents = [Whitespace("")]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 def tokeneater(type, token, start, end, line,
 | 
				
			||||||
 | 
					                INDENT=tokenize.INDENT,
 | 
				
			||||||
 | 
					                DEDENT=tokenize.DEDENT,
 | 
				
			||||||
 | 
					                NEWLINE=tokenize.NEWLINE,
 | 
				
			||||||
 | 
					                JUNK=(tokenize.COMMENT, tokenize.NL) ):
 | 
				
			||||||
 | 
					     global indents, check_equal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     if type == NEWLINE:
 | 
				
			||||||
 | 
					         # a program statement, or ENDMARKER, will eventually follow,
 | 
				
			||||||
 | 
					         # after some (possibly empty) run of tokens of the form
 | 
				
			||||||
 | 
					         #     (NL | COMMENT)* (INDENT | DEDENT+)?
 | 
				
			||||||
 | 
					         # If an INDENT appears, setting check_equal is wrong, and will
 | 
				
			||||||
 | 
					         # be undone when we see the INDENT.
 | 
				
			||||||
 | 
					         check_equal = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     elif type == INDENT:
 | 
				
			||||||
 | 
					         check_equal = 0
 | 
				
			||||||
 | 
					         thisguy = Whitespace(token)
 | 
				
			||||||
 | 
					         if not indents[-1].less(thisguy):
 | 
				
			||||||
 | 
					             witness = indents[-1].not_less_witness(thisguy)
 | 
				
			||||||
 | 
					             msg = "indent not greater e.g. " + format_witnesses(witness)
 | 
				
			||||||
 | 
					             raise NannyNag(start[0], msg, line)
 | 
				
			||||||
 | 
					         indents.append(thisguy)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     elif type == DEDENT:
 | 
				
			||||||
 | 
					         # there's nothing we need to check here!  what's important is
 | 
				
			||||||
 | 
					         # that when the run of DEDENTs ends, the indentation of the
 | 
				
			||||||
 | 
					         # program statement (or ENDMARKER) that triggered the run is
 | 
				
			||||||
 | 
					         # equal to what's left at the top of the indents stack
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         # Ouch!  This assert triggers if the last line of the source
 | 
				
			||||||
 | 
					         # is indented *and* lacks a newline -- then DEDENTs pop out
 | 
				
			||||||
 | 
					         # of thin air.
 | 
				
			||||||
 | 
					         # assert check_equal  # else no earlier NEWLINE, or an earlier INDENT
 | 
				
			||||||
 | 
					         check_equal = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         del indents[-1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     elif check_equal and type not in JUNK:
 | 
				
			||||||
 | 
					         # this is the first "real token" following a NEWLINE, so it
 | 
				
			||||||
 | 
					         # must be the first token of the next program statement, or an
 | 
				
			||||||
 | 
					         # ENDMARKER; the "line" argument exposes the leading whitespace
 | 
				
			||||||
 | 
					         # for this statement; in the case of ENDMARKER, line is an empty
 | 
				
			||||||
 | 
					         # string, so will properly match the empty string with which the
 | 
				
			||||||
 | 
					         # "indents" stack was seeded
 | 
				
			||||||
 | 
					         check_equal = 0
 | 
				
			||||||
 | 
					         thisguy = Whitespace(line)
 | 
				
			||||||
 | 
					         if not indents[-1].equal(thisguy):
 | 
				
			||||||
 | 
					             witness = indents[-1].not_equal_witness(thisguy)
 | 
				
			||||||
 | 
					             msg = "indent not equal e.g. " + format_witnesses(witness)
 | 
				
			||||||
 | 
					             raise NannyNag(start[0], msg, line)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					else:
 | 
				
			||||||
 | 
					 # unpatched version of tokenize
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 nesting_level = 0
 | 
				
			||||||
 | 
					 indents = []
 | 
				
			||||||
 | 
					 check_equal = 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 def reset_globals():
 | 
				
			||||||
 | 
					     global nesting_level, indents, check_equal
 | 
				
			||||||
 | 
					     nesting_level = check_equal = 0
 | 
				
			||||||
 | 
					     indents = [Whitespace("")]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 def tokeneater(type, token, start, end, line,
 | 
				
			||||||
 | 
					                INDENT=tokenize.INDENT,
 | 
				
			||||||
 | 
					                DEDENT=tokenize.DEDENT,
 | 
				
			||||||
 | 
					                NEWLINE=tokenize.NEWLINE,
 | 
				
			||||||
 | 
					                COMMENT=tokenize.COMMENT,
 | 
				
			||||||
 | 
					                OP=tokenize.OP):
 | 
				
			||||||
 | 
					     global nesting_level, indents, check_equal
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     if type == INDENT:
 | 
				
			||||||
 | 
					         check_equal = 0
 | 
				
			||||||
 | 
					         thisguy = Whitespace(token)
 | 
				
			||||||
 | 
					         if not indents[-1].less(thisguy):
 | 
				
			||||||
 | 
					             witness = indents[-1].not_less_witness(thisguy)
 | 
				
			||||||
 | 
					             msg = "indent not greater e.g. " + format_witnesses(witness)
 | 
				
			||||||
 | 
					             raise NannyNag(start[0], msg, line)
 | 
				
			||||||
 | 
					         indents.append(thisguy)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     elif type == DEDENT:
 | 
				
			||||||
 | 
					         del indents[-1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     elif type == NEWLINE:
 | 
				
			||||||
 | 
					         if nesting_level == 0:
 | 
				
			||||||
 | 
					             check_equal = 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     elif type == COMMENT:
 | 
				
			||||||
 | 
					         pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     elif check_equal:
 | 
				
			||||||
 | 
					         check_equal = 0
 | 
				
			||||||
 | 
					         thisguy = Whitespace(line)
 | 
				
			||||||
 | 
					         if not indents[-1].equal(thisguy):
 | 
				
			||||||
 | 
					             witness = indents[-1].not_equal_witness(thisguy)
 | 
				
			||||||
 | 
					             msg = "indent not equal e.g. " + format_witnesses(witness)
 | 
				
			||||||
 | 
					             raise NannyNag(start[0], msg, line)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     if type == OP and token in ('{', '[', '('):
 | 
				
			||||||
 | 
					         nesting_level = nesting_level + 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					     elif type == OP and token in ('}', ']', ')'):
 | 
				
			||||||
 | 
					         if nesting_level == 0:
 | 
				
			||||||
 | 
					             raise NannyNag(start[0],
 | 
				
			||||||
 | 
					                            "unbalanced bracket '" + token + "'",
 | 
				
			||||||
 | 
					                            line)
 | 
				
			||||||
 | 
					         nesting_level = nesting_level - 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    main()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										31
									
								
								Lib/idlelib/testcode.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								Lib/idlelib/testcode.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					import string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def f():
 | 
				
			||||||
 | 
					    a = 0
 | 
				
			||||||
 | 
					    b = 1
 | 
				
			||||||
 | 
					    c = 2
 | 
				
			||||||
 | 
					    d = 3
 | 
				
			||||||
 | 
					    e = 4
 | 
				
			||||||
 | 
					    g()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def g():
 | 
				
			||||||
 | 
					    h()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def h():
 | 
				
			||||||
 | 
					    i()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def i():
 | 
				
			||||||
 | 
					    j()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def j():
 | 
				
			||||||
 | 
					    k()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def k():
 | 
				
			||||||
 | 
					    l()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					l = lambda: test()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def test():
 | 
				
			||||||
 | 
					    string.capwords(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					f()
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue