annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/idlelib/outwin.py @ 68:5028fdace37b

planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author jpayne
date Tue, 18 Mar 2025 16:23:26 -0400
parents
children
rev   line source
jpayne@68 1 """Editor window that can serve as an output file.
jpayne@68 2 """
jpayne@68 3
jpayne@68 4 import re
jpayne@68 5
jpayne@68 6 from tkinter import messagebox
jpayne@68 7
jpayne@68 8 from idlelib.editor import EditorWindow
jpayne@68 9 from idlelib import iomenu
jpayne@68 10
jpayne@68 11
jpayne@68 12 file_line_pats = [
jpayne@68 13 # order of patterns matters
jpayne@68 14 r'file "([^"]*)", line (\d+)',
jpayne@68 15 r'([^\s]+)\((\d+)\)',
jpayne@68 16 r'^(\s*\S.*?):\s*(\d+):', # Win filename, maybe starting with spaces
jpayne@68 17 r'([^\s]+):\s*(\d+):', # filename or path, ltrim
jpayne@68 18 r'^\s*(\S.*?):\s*(\d+):', # Win abs path with embedded spaces, ltrim
jpayne@68 19 ]
jpayne@68 20
jpayne@68 21 file_line_progs = None
jpayne@68 22
jpayne@68 23
jpayne@68 24 def compile_progs():
jpayne@68 25 "Compile the patterns for matching to file name and line number."
jpayne@68 26 global file_line_progs
jpayne@68 27 file_line_progs = [re.compile(pat, re.IGNORECASE)
jpayne@68 28 for pat in file_line_pats]
jpayne@68 29
jpayne@68 30
jpayne@68 31 def file_line_helper(line):
jpayne@68 32 """Extract file name and line number from line of text.
jpayne@68 33
jpayne@68 34 Check if line of text contains one of the file/line patterns.
jpayne@68 35 If it does and if the file and line are valid, return
jpayne@68 36 a tuple of the file name and line number. If it doesn't match
jpayne@68 37 or if the file or line is invalid, return None.
jpayne@68 38 """
jpayne@68 39 if not file_line_progs:
jpayne@68 40 compile_progs()
jpayne@68 41 for prog in file_line_progs:
jpayne@68 42 match = prog.search(line)
jpayne@68 43 if match:
jpayne@68 44 filename, lineno = match.group(1, 2)
jpayne@68 45 try:
jpayne@68 46 f = open(filename, "r")
jpayne@68 47 f.close()
jpayne@68 48 break
jpayne@68 49 except OSError:
jpayne@68 50 continue
jpayne@68 51 else:
jpayne@68 52 return None
jpayne@68 53 try:
jpayne@68 54 return filename, int(lineno)
jpayne@68 55 except TypeError:
jpayne@68 56 return None
jpayne@68 57
jpayne@68 58
jpayne@68 59 class OutputWindow(EditorWindow):
jpayne@68 60 """An editor window that can serve as an output file.
jpayne@68 61
jpayne@68 62 Also the future base class for the Python shell window.
jpayne@68 63 This class has no input facilities.
jpayne@68 64
jpayne@68 65 Adds binding to open a file at a line to the text widget.
jpayne@68 66 """
jpayne@68 67
jpayne@68 68 # Our own right-button menu
jpayne@68 69 rmenu_specs = [
jpayne@68 70 ("Cut", "<<cut>>", "rmenu_check_cut"),
jpayne@68 71 ("Copy", "<<copy>>", "rmenu_check_copy"),
jpayne@68 72 ("Paste", "<<paste>>", "rmenu_check_paste"),
jpayne@68 73 (None, None, None),
jpayne@68 74 ("Go to file/line", "<<goto-file-line>>", None),
jpayne@68 75 ]
jpayne@68 76
jpayne@68 77 allow_code_context = False
jpayne@68 78
jpayne@68 79 def __init__(self, *args):
jpayne@68 80 EditorWindow.__init__(self, *args)
jpayne@68 81 self.text.bind("<<goto-file-line>>", self.goto_file_line)
jpayne@68 82
jpayne@68 83 # Customize EditorWindow
jpayne@68 84 def ispythonsource(self, filename):
jpayne@68 85 "Python source is only part of output: do not colorize."
jpayne@68 86 return False
jpayne@68 87
jpayne@68 88 def short_title(self):
jpayne@68 89 "Customize EditorWindow title."
jpayne@68 90 return "Output"
jpayne@68 91
jpayne@68 92 def maybesave(self):
jpayne@68 93 "Customize EditorWindow to not display save file messagebox."
jpayne@68 94 return 'yes' if self.get_saved() else 'no'
jpayne@68 95
jpayne@68 96 # Act as output file
jpayne@68 97 def write(self, s, tags=(), mark="insert"):
jpayne@68 98 """Write text to text widget.
jpayne@68 99
jpayne@68 100 The text is inserted at the given index with the provided
jpayne@68 101 tags. The text widget is then scrolled to make it visible
jpayne@68 102 and updated to display it, giving the effect of seeing each
jpayne@68 103 line as it is added.
jpayne@68 104
jpayne@68 105 Args:
jpayne@68 106 s: Text to insert into text widget.
jpayne@68 107 tags: Tuple of tag strings to apply on the insert.
jpayne@68 108 mark: Index for the insert.
jpayne@68 109
jpayne@68 110 Return:
jpayne@68 111 Length of text inserted.
jpayne@68 112 """
jpayne@68 113 if isinstance(s, bytes):
jpayne@68 114 s = s.decode(iomenu.encoding, "replace")
jpayne@68 115 self.text.insert(mark, s, tags)
jpayne@68 116 self.text.see(mark)
jpayne@68 117 self.text.update()
jpayne@68 118 return len(s)
jpayne@68 119
jpayne@68 120 def writelines(self, lines):
jpayne@68 121 "Write each item in lines iterable."
jpayne@68 122 for line in lines:
jpayne@68 123 self.write(line)
jpayne@68 124
jpayne@68 125 def flush(self):
jpayne@68 126 "No flushing needed as write() directly writes to widget."
jpayne@68 127 pass
jpayne@68 128
jpayne@68 129 def showerror(self, *args, **kwargs):
jpayne@68 130 messagebox.showerror(*args, **kwargs)
jpayne@68 131
jpayne@68 132 def goto_file_line(self, event=None):
jpayne@68 133 """Handle request to open file/line.
jpayne@68 134
jpayne@68 135 If the selected or previous line in the output window
jpayne@68 136 contains a file name and line number, then open that file
jpayne@68 137 name in a new window and position on the line number.
jpayne@68 138
jpayne@68 139 Otherwise, display an error messagebox.
jpayne@68 140 """
jpayne@68 141 line = self.text.get("insert linestart", "insert lineend")
jpayne@68 142 result = file_line_helper(line)
jpayne@68 143 if not result:
jpayne@68 144 # Try the previous line. This is handy e.g. in tracebacks,
jpayne@68 145 # where you tend to right-click on the displayed source line
jpayne@68 146 line = self.text.get("insert -1line linestart",
jpayne@68 147 "insert -1line lineend")
jpayne@68 148 result = file_line_helper(line)
jpayne@68 149 if not result:
jpayne@68 150 self.showerror(
jpayne@68 151 "No special line",
jpayne@68 152 "The line you point at doesn't look like "
jpayne@68 153 "a valid file name followed by a line number.",
jpayne@68 154 parent=self.text)
jpayne@68 155 return
jpayne@68 156 filename, lineno = result
jpayne@68 157 self.flist.gotofileline(filename, lineno)
jpayne@68 158
jpayne@68 159
jpayne@68 160 # These classes are currently not used but might come in handy
jpayne@68 161 class OnDemandOutputWindow:
jpayne@68 162
jpayne@68 163 tagdefs = {
jpayne@68 164 # XXX Should use IdlePrefs.ColorPrefs
jpayne@68 165 "stdout": {"foreground": "blue"},
jpayne@68 166 "stderr": {"foreground": "#007700"},
jpayne@68 167 }
jpayne@68 168
jpayne@68 169 def __init__(self, flist):
jpayne@68 170 self.flist = flist
jpayne@68 171 self.owin = None
jpayne@68 172
jpayne@68 173 def write(self, s, tags, mark):
jpayne@68 174 if not self.owin:
jpayne@68 175 self.setup()
jpayne@68 176 self.owin.write(s, tags, mark)
jpayne@68 177
jpayne@68 178 def setup(self):
jpayne@68 179 self.owin = owin = OutputWindow(self.flist)
jpayne@68 180 text = owin.text
jpayne@68 181 for tag, cnf in self.tagdefs.items():
jpayne@68 182 if cnf:
jpayne@68 183 text.tag_configure(tag, **cnf)
jpayne@68 184 text.tag_raise('sel')
jpayne@68 185 self.write = self.owin.write
jpayne@68 186
jpayne@68 187 if __name__ == '__main__':
jpayne@68 188 from unittest import main
jpayne@68 189 main('idlelib.idle_test.test_outwin', verbosity=2, exit=False)