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