1 # changes by dscherer@cmu.edu
2 # - OutputWindow and OnDemandOutputWindow have been hastily
3 # extended to provide readline() support, an "iomark" separate
4 # from the "insert" cursor, and scrolling to clear the window.
5 # These changes are used by the ExecBinding module to provide
6 # standard input and output for user programs. Many of the new
7 # features are very similar to features of PyShell, which is a
8 # subclass of OutputWindow. Someone should make some sense of
12 from EditorWindow
import EditorWindow
16 from UndoDelegator
import UndoDelegator
18 class OutputUndoDelegator(UndoDelegator
):
20 # Forbid insert/delete before the I/O mark, in the blank lines after
21 # the output, or *anywhere* if we are not presently doing user input
22 def insert(self
, index
, chars
, tags
=None):
24 if (self
.delegate
.compare(index
, "<", "iomark") or
25 self
.delegate
.compare(index
, ">", "endmark") or
26 (index
!="iomark" and not self
.reading
)):
31 UndoDelegator
.insert(self
, index
, chars
, tags
)
32 def delete(self
, index1
, index2
=None):
34 if (self
.delegate
.compare(index1
, "<", "iomark") or
35 self
.delegate
.compare(index1
, ">", "endmark") or
36 (index2
and self
.delegate
.compare(index2
, ">=", "endmark")) or
42 UndoDelegator
.delete(self
, index1
, index2
)
44 class OutputWindow(EditorWindow
):
45 """An editor window that can serve as an input and output file.
46 The input support has been rather hastily hacked in, and should
50 UndoDelegator
= OutputUndoDelegator
53 def __init__(self
, *args
, **keywords
):
54 if keywords
.has_key('source_window'):
55 self
.source_window
= keywords
['source_window']
56 apply(EditorWindow
.__init
__, (self
,) + args
)
57 self
.text
.bind("<<goto-file-line>>", self
.goto_file_line
)
58 self
.text
.bind("<<newline-and-indent>>", self
.enter_callback
)
59 self
.text
.mark_set("iomark","1.0")
60 self
.text
.mark_gravity("iomark", LEFT
)
61 self
.text
.mark_set("endmark","1.0")
63 # Customize EditorWindow
65 def ispythonsource(self
, filename
):
66 # No colorization needed
69 def short_title(self
):
76 # Override base class method -- don't ask any questions
82 # Act as input file - incomplete
84 def set_line_and_column(self
, event
=None):
85 index
= self
.text
.index(INSERT
)
86 if (self
.text
.compare(index
, ">", "endmark")):
87 self
.text
.mark_set("insert", "endmark")
88 self
.text
.see("insert")
89 EditorWindow
.set_line_and_column(self
)
98 self
.reading
= self
.undo
.reading
= 1
99 self
.text
.mark_set("insert", "iomark")
100 self
.text
.see("insert")
103 self
.reading
= self
.undo
.reading
= save
104 line
= self
.text
.get("input", "iomark")
107 raise KeyboardInterrupt
115 return EditorWindow
.close(self
)
122 def enter_callback(self
, event
):
123 if self
.reading
and self
.text
.compare("insert", ">=", "iomark"):
124 self
.text
.mark_set("input", "iomark")
125 self
.text
.mark_set("iomark", "insert")
126 self
.write('\n',"iomark")
127 self
.text
.tag_add("stdin", "input", "iomark")
128 self
.text
.update_idletasks()
129 self
.top
.quit() # Break out of recursive mainloop() in raw_input()
135 def write(self
, s
, tags
=(), mark
="iomark"):
136 self
.text
.mark_gravity(mark
, RIGHT
)
137 self
.text
.insert(mark
, str(s
), tags
)
138 self
.text
.mark_gravity(mark
, LEFT
)
142 def writelines(self
, l
):
148 # Our own right-button menu
151 ("Go to file/line", "<<goto-file-line>>"),
155 r
'file "([^"]*)", line (\d+)',
156 r
'([^\s]+)\((\d+)\)',
157 r
'([^\s]+):\s*(\d+):',
160 file_line_progs
= None
162 def goto_file_line(self
, event
=None):
163 if self
.file_line_progs
is None:
165 for pat
in self
.file_line_pats
:
166 l
.append(re
.compile(pat
, re
.IGNORECASE
))
167 self
.file_line_progs
= l
168 # x, y = self.event.x, self.event.y
169 # self.text.mark_set("insert", "@%d,%d" % (x, y))
170 line
= self
.text
.get("insert linestart", "insert lineend")
171 result
= self
._file
_line
_helper
(line
)
173 # Try the previous line. This is handy e.g. in tracebacks,
174 # where you tend to right-click on the displayed source line
175 line
= self
.text
.get("insert -1line linestart",
176 "insert -1line lineend")
177 result
= self
._file
_line
_helper
(line
)
179 tkMessageBox
.showerror(
181 "The line you point at doesn't look like "
182 "a valid file name followed by a line number.",
185 filename
, lineno
= result
186 edit
= self
.untitled(filename
) or self
.flist
.open(filename
)
187 edit
.gotoline(lineno
)
190 def untitled(self
, filename
):
191 if filename
!='Untitled' or not self
.source_window
or self
.source_window
.io
.filename
:
193 return self
.source_window
195 def _file_line_helper(self
, line
):
196 for prog
in self
.file_line_progs
:
197 m
= prog
.search(line
)
202 filename
, lineno
= m
.group(1, 2)
203 if not self
.untitled(filename
):
205 f
= open(filename
, "r")
210 return filename
, int(lineno
)
214 # This classes now used by ExecBinding.py:
216 class OnDemandOutputWindow
:
220 # XXX Should use IdlePrefs.ColorPrefs
221 "stdin": {"foreground": "black"},
222 "stdout": {"foreground": "blue"},
223 "stderr": {"foreground": "red"},
226 def __init__(self
, flist
):
229 self
.title
= "Output"
230 self
.close_hook
= None
231 self
.old_close
= None
239 def set_title(self
, title
):
241 if self
.owin
and self
.owin
.text
:
242 self
.owin
.saved_change_hook()
244 def write(self
, s
, tags
=(), mark
="iomark"):
245 if not self
.owin
or not self
.owin
.text
:
247 self
.owin
.write(s
, tags
, mark
)
250 if not self
.owin
or not self
.owin
.text
:
252 return self
.owin
.readline()
254 def scroll_clear(self
):
255 if self
.owin
and self
.owin
.text
:
256 lineno
= self
.owin
.getlineno("endmark")
257 self
.owin
.text
.mark_set("insert","endmark")
258 self
.owin
.text
.yview(float(lineno
))
262 self
.owin
= owin
= OutputWindow(self
.flist
, source_window
= self
.source_window
)
263 owin
.short_title
= lambda self
=self
: self
.title
266 self
.old_close
= owin
.close_hook
267 owin
.close_hook
= self
.owclose
269 # xxx Bad hack: 50 blank lines at the bottom so that
270 # we can scroll the top of the window to the output
271 # cursor in scroll_clear(). There must be a better way...
272 owin
.text
.mark_gravity('endmark', LEFT
)
273 owin
.text
.insert('iomark', '\n'*50)
274 owin
.text
.mark_gravity('endmark', RIGHT
)
276 for tag
, cnf
in self
.tagdefs
.items():
278 apply(text
.tag_configure
, (tag
,), cnf
)
279 text
.tag_raise('sel')