diff --git a/Lib/idlelib/Debugger.py b/Lib/idlelib/Debugger.py index a82fdbb21b5..30d0002eaf6 100644 --- a/Lib/idlelib/Debugger.py +++ b/Lib/idlelib/Debugger.py @@ -331,7 +331,7 @@ class Debugger: for editwin in pyshell_edit_windows: filename = editwin.io.filename try: - for lineno in editwin.get_current_breaks(): + for lineno in editwin.breakpoints: self.set_breakpoint_here(filename, lineno) except AttributeError: continue diff --git a/Lib/idlelib/IOBinding.py b/Lib/idlelib/IOBinding.py index 594ecf64719..a90157ea0c7 100644 --- a/Lib/idlelib/IOBinding.py +++ b/Lib/idlelib/IOBinding.py @@ -13,28 +13,9 @@ import tempfile import tkFileDialog import tkMessageBox import re + from configHandler import idleConf -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - -#$ event <> -#$ win -#$ unix - try: from codecs import BOM_UTF8 except ImportError: @@ -85,11 +66,12 @@ else: encoding = encoding.lower() coding_re = re.compile("coding[:=]\s*([-\w_.]+)") + def coding_spec(str): - """Return the encoding declaration according to PEP 263. - Raise LookupError if the encoding is declared but unknown.""" + Raise LookupError if the encoding is declared but unknown. + """ # Only consider the first two lines str = str.split("\n")[:2] str = "\n".join(str) @@ -107,6 +89,7 @@ def coding_spec(str): raise LookupError, "Unknown encoding "+name return name + class IOBinding: def __init__(self, editwin): @@ -218,14 +201,14 @@ class IOBinding: self.set_filename(filename) self.text.mark_set("insert", "1.0") self.text.see("insert") - self.updaterecentfileslist(filename) return True def decode(self, chars): - # Try to create a Unicode string. If that fails, let Tcl try - # its best + """Create a Unicode string + If that fails, let Tcl try its best + """ # Check presence of a UTF-8 signature first if chars.startswith(BOM_UTF8): try: @@ -237,7 +220,6 @@ class IOBinding: # Indicates that this file originally had a BOM self.fileencoding = BOM_UTF8 return chars - # Next look for coding specification try: enc = coding_spec(chars) @@ -248,19 +230,16 @@ class IOBinding: "installation. The file may not display correctly" % name, master = self.text) enc = None - if enc: try: return unicode(chars, enc) except UnicodeError: pass - # If it is ASCII, we need not to record anything try: return unicode(chars, 'ascii') except UnicodeError: pass - # Finally, try the locale's encoding. This is deprecated; # the user should declare a non-ASCII encoding try: @@ -295,8 +274,8 @@ class IOBinding: else: if self.writefile(self.filename): self.set_saved(1) + self.editwin.store_file_breaks() self.text.focus_set() - return "break" def save_as(self, event): @@ -305,8 +284,8 @@ class IOBinding: if self.writefile(filename): self.set_filename(filename) self.set_saved(1) + self.editwin.store_file_breaks() self.text.focus_set() - self.updaterecentfileslist(filename) return "break" @@ -315,7 +294,6 @@ class IOBinding: if filename: self.writefile(filename) self.text.focus_set() - self.updaterecentfileslist(filename) return "break" @@ -326,7 +304,6 @@ class IOBinding: f = open(filename, "w") f.write(chars) f.close() - ## print "saved to", `filename` return True except IOError, msg: tkMessageBox.showerror("I/O Error", str(msg), @@ -338,14 +315,12 @@ class IOBinding: # This is either plain ASCII, or Tk was returning mixed-encoding # text to us. Don't try to guess further. return chars - # See whether there is anything non-ASCII in it. # If not, no need to figure out the encoding. try: return chars.encode('ascii') except UnicodeError: pass - # If there is an encoding declared, try this first. try: enc = coding_spec(chars) @@ -358,17 +333,14 @@ class IOBinding: return chars.encode(enc) except UnicodeError: failed = "Invalid encoding '%s'" % enc - if failed: tkMessageBox.showerror( "I/O Error", "%s. Saving as UTF-8" % failed, master = self.text) - # If there was a UTF-8 signature, use that. This should not fail if self.fileencoding == BOM_UTF8 or failed: return BOM_UTF8 + chars.encode("utf-8") - # Try the original file encoding next, if any if self.fileencoding: try: @@ -380,7 +352,6 @@ class IOBinding: % self.fileencoding, master = self.text) return BOM_UTF8 + chars.encode("utf-8") - # Nothing was declared, and we had not determined an encoding # on loading. Recommend an encoding line. try: @@ -469,11 +440,8 @@ class IOBinding: filetypes=self.filetypes) return self.savedialog.show(initialdir=dir, initialfile=base) - def updaterecentfileslist(self,filename): - # - # Updates recent file list on all editor windows - # + "Update recent file list on all editor windows" self.editwin.UpdateRecentFilesList(filename) def test(): diff --git a/Lib/idlelib/PyShell.py b/Lib/idlelib/PyShell.py index cf93613e33f..f6e85f74287 100644 --- a/Lib/idlelib/PyShell.py +++ b/Lib/idlelib/PyShell.py @@ -67,10 +67,6 @@ linecache.checkcache = extended_linecache_checkcache class PyShellEditorWindow(EditorWindow): "Regular text edit window when a shell is present" - # XXX KBK 10Dec02 Breakpoints are currently removed if module is modified. - # In the future, it may be possible to preserve breakpoints by changing - # their line numbers as a module is modified. - def __init__(self, *args): self.breakpoints = [] apply(EditorWindow.__init__, (self,) + args) @@ -78,11 +74,12 @@ class PyShellEditorWindow(EditorWindow): self.text.bind("<>", self.clear_breakpoint_here) self.text.bind("<>", self.flist.open_shell) - self.breakpointPath=os.path.join(idleConf.GetUserCfgDir(), 'breakpoints.lst') - + self.breakpointPath = os.path.join(idleConf.GetUserCfgDir(), + 'breakpoints.lst') # whenever a file is changed, restore breakpoints if self.io.filename: self.restore_file_breaks() - def filename_changed_hook(old_hook=self.io.filename_change_hook,self=self): + def filename_changed_hook(old_hook=self.io.filename_change_hook, + self=self): self.restore_file_breaks() old_hook() self.io.set_filename_change_hook(filename_changed_hook) @@ -148,49 +145,82 @@ class PyShellEditorWindow(EditorWindow): pass def store_file_breaks(self): - if not self.breakpoints: - return - filename=self.io.filename + "Save breakpoints when file is saved" + # XXX 13 Dec 2002 KBK Currently the file must be saved before it can + # be run. The breaks are saved at that time. If we introduce + # a temporary file save feature the save breaks functionality + # needs to be re-verified, since the breaks at the time the + # temp file is created may differ from the breaks at the last + # permanent save of the file. A break introduced after a save + # will be effective, but not persistent. This is necessary to + # keep the saved breaks synched with the saved file. + # + # Breakpoints are set as tagged ranges in the text. Certain + # kinds of edits cause these ranges to be deleted: Inserting + # or deleting a line just before a breakpoint, and certain + # deletions prior to a breakpoint. These issues need to be + # investigated and understood. It's not clear if they are + # Tk issues or IDLE issues, or whether they can actually + # be fixed. Since a modified file has to be saved before it is + # run, and since self.breakpoints (from which the subprocess + # debugger is loaded) is updated during the save, the visible + # breaks stay synched with the subprocess even if one of these + # unexpected breakpoint deletions occurs. + breaks = self.breakpoints + filename = self.io.filename try: - lines=open(self.breakpointPath,"r").readlines() + lines = open(self.breakpointPath,"r").readlines() except IOError: - lines=[] - new_file=open(self.breakpointPath,"w") + lines = [] + new_file = open(self.breakpointPath,"w") for line in lines: - if not line.startswith(filename+"="): + if not line.startswith(filename + '='): new_file.write(line) - new_file.write(filename+"="+`self.get_current_breaks()`+"\n") + self.update_breakpoints() + breaks = self.breakpoints + if breaks: + new_file.write(filename + '=' + str(breaks) + '\n') new_file.close() def restore_file_breaks(self): self.text.update() # this enables setting "BREAK" tags to be visible - filename=self.io.filename + filename = self.io.filename + if filename is None: + return if os.path.isfile(self.breakpointPath): - lines=open(self.breakpointPath,"r").readlines() + lines = open(self.breakpointPath,"r").readlines() for line in lines: - if line.startswith(filename+"="): - breakpoint_linenumbers=eval(line[len(filename)+1:]) + if line.startswith(filename + '='): + breakpoint_linenumbers = eval(line[len(filename)+1:]) for breakpoint_linenumber in breakpoint_linenumbers: self.set_breakpoint(breakpoint_linenumber) - def get_current_breaks(self): - # - # retrieves all the breakpoints in the current window - # + def update_breakpoints(self): + "Retrieves all the breakpoints in the current window" text = self.text - lines = text.tag_ranges("BREAK") - result = [int(float((lines[i]))) for i in range(0,len(lines),2)] - return result - - def saved_change_hook(self): - "Extend base method - clear breaks if module is modified" - if not self.get_saved(): - self.clear_file_breaks() - EditorWindow.saved_change_hook(self) + ranges = text.tag_ranges("BREAK") + linenumber_list = self.ranges_to_linenumbers(ranges) + self.breakpoints = linenumber_list + + def ranges_to_linenumbers(self, ranges): + lines = [] + for index in range(0, len(ranges), 2): + lineno = int(float(ranges[index])) + end = int(float(ranges[index+1])) + while lineno < end: + lines.append(lineno) + lineno += 1 + return lines + +# XXX 13 Dec 2020 KBK Not used currently +# def saved_change_hook(self): +# "Extend base method - clear breaks if module is modified" +# if not self.get_saved(): +# self.clear_file_breaks() +# EditorWindow.saved_change_hook(self) def _close(self): "Extend base method - clear breaks when module is closed" - self.store_file_breaks() self.clear_file_breaks() EditorWindow._close(self)