annotate CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/python3.8/idlelib/outwin.py @ 69:33d812a61356

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