blob: e7d747c377b2c35cbd2c1bfbff446ed0a943c3c0 [file] [log] [blame]
David Scherer7aced172000-08-15 01:13:23 +00001# changes by dscherer@cmu.edu
2# - IOBinding.open() replaces the current window with the opened file,
3# if the current window is both unmodified and unnamed
4# - IOBinding.loadfile() interprets Windows, UNIX, and Macintosh
5# end-of-line conventions, instead of relying on the standard library,
6# which will only understand the local convention.
7
8import os
Kurt B. Kaiser01166da2002-09-16 22:03:37 +00009import types
Serhiy Storchakaeebcb5f2013-01-12 18:12:27 +020010import pipes
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000011import sys
12import codecs
Steven M. Gava7981ce52002-06-11 04:45:34 +000013import tempfile
Georg Brandl6634bf22008-05-20 07:13:37 +000014import tkFileDialog
15import tkMessageBox
David Scherer7aced172000-08-15 01:13:23 +000016import re
Georg Brandl6634bf22008-05-20 07:13:37 +000017from Tkinter import *
18from SimpleDialog import SimpleDialog
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000019
Florent Xiclunad630c042010-04-02 07:24:52 +000020from idlelib.configHandler import idleConf
David Scherer7aced172000-08-15 01:13:23 +000021
Terry Jan Reedy57ac6232014-10-06 00:13:51 -040022from codecs import BOM_UTF8
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000023
24# Try setting the locale, so that we can find out
25# what encoding to use
26try:
27 import locale
28 locale.setlocale(locale.LC_CTYPE, "")
Kurt B. Kaiser188e25f2003-11-25 05:01:00 +000029except (ImportError, locale.Error):
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000030 pass
31
Martin v. Löwis307021f2005-11-27 16:59:04 +000032# Encoding for file names
33filesystemencoding = sys.getfilesystemencoding()
34
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000035encoding = "ascii"
36if sys.platform == 'win32':
37 # On Windows, we could use "mbcs". However, to give the user
38 # a portable encoding name, we need to find the code page
39 try:
40 encoding = locale.getdefaultlocale()[1]
41 codecs.lookup(encoding)
42 except LookupError:
43 pass
44else:
45 try:
46 # Different things can fail here: the locale module may not be
47 # loaded, it may not offer nl_langinfo, or CODESET, or the
48 # resulting codeset may be unknown to Python. We ignore all
49 # these problems, falling back to ASCII
50 encoding = locale.nl_langinfo(locale.CODESET)
Martin v. Löwisa9170c72004-08-12 13:14:52 +000051 if encoding is None or encoding is '':
Tony Lowndse555fc72002-09-23 01:01:20 +000052 # situation occurs on Mac OS X
53 encoding = 'ascii'
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000054 codecs.lookup(encoding)
55 except (NameError, AttributeError, LookupError):
56 # Try getdefaultlocale well: it parses environment variables,
57 # which may give a clue. Unfortunately, getdefaultlocale has
58 # bugs that can cause ValueError.
59 try:
60 encoding = locale.getdefaultlocale()[1]
Martin v. Löwisa9170c72004-08-12 13:14:52 +000061 if encoding is None or encoding is '':
Tony Lowndse555fc72002-09-23 01:01:20 +000062 # situation occurs on Mac OS X
63 encoding = 'ascii'
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000064 codecs.lookup(encoding)
65 except (ValueError, LookupError):
66 pass
67
68encoding = encoding.lower()
69
Serhiy Storchakae4818f62013-09-17 10:09:08 +030070coding_re = re.compile(r'^[ \t\f]*#.*coding[:=][ \t]*([-\w.]+)')
Serhiy Storchaka3eb554f2014-09-05 10:22:05 +030071blank_re = re.compile(r'^[ \t\f]*(?:[#\r\n]|$)')
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000072
Kurt B. Kaisera053f332003-05-10 00:49:56 +000073class EncodingMessage(SimpleDialog):
74 "Inform user that an encoding declaration is needed."
75 def __init__(self, master, enc):
76 self.should_edit = False
Kurt B. Kaiser47674012003-05-18 02:24:32 +000077
Kurt B. Kaisera053f332003-05-10 00:49:56 +000078 self.root = top = Toplevel(master)
79 top.bind("<Return>", self.return_event)
80 top.bind("<Escape>", self.do_ok)
81 top.protocol("WM_DELETE_WINDOW", self.wm_delete_window)
82 top.wm_title("I/O Warning")
83 top.wm_iconname("I/O Warning")
84 self.top = top
85
86 l1 = Label(top,
87 text="Non-ASCII found, yet no encoding declared. Add a line like")
88 l1.pack(side=TOP, anchor=W)
89 l2 = Entry(top, font="courier")
90 l2.insert(0, "# -*- coding: %s -*-" % enc)
91 # For some reason, the text is not selectable anymore if the
92 # widget is disabled.
93 # l2['state'] = DISABLED
94 l2.pack(side=TOP, anchor = W, fill=X)
95 l3 = Label(top, text="to your file\n"
96 "Choose OK to save this file as %s\n"
97 "Edit your general options to silence this warning" % enc)
98 l3.pack(side=TOP, anchor = W)
99
100 buttons = Frame(top)
101 buttons.pack(side=TOP, fill=X)
102 # Both return and cancel mean the same thing: do nothing
103 self.default = self.cancel = 0
104 b1 = Button(buttons, text="Ok", default="active",
105 command=self.do_ok)
106 b1.pack(side=LEFT, fill=BOTH, expand=1)
107 b2 = Button(buttons, text="Edit my file",
108 command=self.do_edit)
109 b2.pack(side=LEFT, fill=BOTH, expand=1)
Kurt B. Kaiser47674012003-05-18 02:24:32 +0000110
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000111 self._set_transient(master)
112
113 def do_ok(self):
114 self.done(0)
115
116 def do_edit(self):
117 self.done(1)
118
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000119def coding_spec(str):
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000120 """Return the encoding declaration according to PEP 263.
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000121
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000122 Raise LookupError if the encoding is declared but unknown.
123 """
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000124 # Only consider the first two lines
Serhiy Storchaka1c760ca2013-10-29 10:15:09 +0200125 lst = str.split("\n", 2)[:2]
Serhiy Storchakae787bce2013-09-17 00:00:46 +0300126 for line in lst:
127 match = coding_re.match(line)
128 if match is not None:
129 break
Serhiy Storchaka3eb554f2014-09-05 10:22:05 +0300130 if not blank_re.match(line):
131 return None
Serhiy Storchakae787bce2013-09-17 00:00:46 +0300132 else:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000133 return None
134 name = match.group(1)
135 # Check whether the encoding is known
136 import codecs
137 try:
138 codecs.lookup(name)
139 except LookupError:
140 # The standard encoding error does not indicate the encoding
141 raise LookupError, "Unknown encoding "+name
142 return name
David Scherer7aced172000-08-15 01:13:23 +0000143
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000144
David Scherer7aced172000-08-15 01:13:23 +0000145class IOBinding:
146
147 def __init__(self, editwin):
148 self.editwin = editwin
149 self.text = editwin.text
150 self.__id_open = self.text.bind("<<open-window-from-file>>", self.open)
151 self.__id_save = self.text.bind("<<save-window>>", self.save)
152 self.__id_saveas = self.text.bind("<<save-window-as-file>>",
153 self.save_as)
154 self.__id_savecopy = self.text.bind("<<save-copy-of-window-as-file>>",
155 self.save_a_copy)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000156 self.fileencoding = None
Steven M. Gava7981ce52002-06-11 04:45:34 +0000157 self.__id_print = self.text.bind("<<print-window>>", self.print_window)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000158
David Scherer7aced172000-08-15 01:13:23 +0000159 def close(self):
160 # Undo command bindings
161 self.text.unbind("<<open-window-from-file>>", self.__id_open)
162 self.text.unbind("<<save-window>>", self.__id_save)
163 self.text.unbind("<<save-window-as-file>>",self.__id_saveas)
164 self.text.unbind("<<save-copy-of-window-as-file>>", self.__id_savecopy)
Steven M. Gava7981ce52002-06-11 04:45:34 +0000165 self.text.unbind("<<print-window>>", self.__id_print)
David Scherer7aced172000-08-15 01:13:23 +0000166 # Break cycles
167 self.editwin = None
168 self.text = None
169 self.filename_change_hook = None
170
171 def get_saved(self):
172 return self.editwin.get_saved()
173
174 def set_saved(self, flag):
175 self.editwin.set_saved(flag)
176
177 def reset_undo(self):
178 self.editwin.reset_undo()
179
180 filename_change_hook = None
181
182 def set_filename_change_hook(self, hook):
183 self.filename_change_hook = hook
184
185 filename = None
Kurt B. Kaiserd2f48612003-06-05 02:34:04 +0000186 dirname = None
David Scherer7aced172000-08-15 01:13:23 +0000187
188 def set_filename(self, filename):
Kurt B. Kaiserd2f48612003-06-05 02:34:04 +0000189 if filename and os.path.isdir(filename):
190 self.filename = None
191 self.dirname = filename
192 else:
193 self.filename = filename
194 self.dirname = None
195 self.set_saved(1)
196 if self.filename_change_hook:
197 self.filename_change_hook()
David Scherer7aced172000-08-15 01:13:23 +0000198
Steven M. Gava1d46e402002-03-27 08:40:46 +0000199 def open(self, event=None, editFile=None):
Terry Jan Reedyeaa7e782012-05-26 20:33:32 -0400200 flist = self.editwin.flist
Terry Jan Reedyf0775132012-06-02 20:22:35 -0400201 # Save in case parent window is closed (ie, during askopenfile()).
Terry Jan Reedyeaa7e782012-05-26 20:33:32 -0400202 if flist:
Steven M. Gava1d46e402002-03-27 08:40:46 +0000203 if not editFile:
204 filename = self.askopenfile()
205 else:
206 filename=editFile
David Scherer7aced172000-08-15 01:13:23 +0000207 if filename:
Terry Jan Reedyf0775132012-06-02 20:22:35 -0400208 # If editFile is valid and already open, flist.open will
209 # shift focus to its existing window.
210 # If the current window exists and is a fresh unnamed,
211 # unmodified editor window (not an interpreter shell),
212 # pass self.loadfile to flist.open so it will load the file
213 # in the current window (if the file is not already open)
214 # instead of a new window.
215 if (self.editwin and
216 not getattr(self.editwin, 'interp', None) and
217 not self.filename and
218 self.get_saved()):
Terry Jan Reedyeaa7e782012-05-26 20:33:32 -0400219 flist.open(filename, self.loadfile)
David Scherer7aced172000-08-15 01:13:23 +0000220 else:
Terry Jan Reedyeaa7e782012-05-26 20:33:32 -0400221 flist.open(filename)
David Scherer7aced172000-08-15 01:13:23 +0000222 else:
Terry Jan Reedyeaa7e782012-05-26 20:33:32 -0400223 if self.text:
224 self.text.focus_set()
David Scherer7aced172000-08-15 01:13:23 +0000225 return "break"
Terry Jan Reedyf0775132012-06-02 20:22:35 -0400226
David Scherer7aced172000-08-15 01:13:23 +0000227 # Code for use outside IDLE:
228 if self.get_saved():
229 reply = self.maybesave()
230 if reply == "cancel":
231 self.text.focus_set()
232 return "break"
Steven M. Gava1d46e402002-03-27 08:40:46 +0000233 if not editFile:
234 filename = self.askopenfile()
235 else:
236 filename=editFile
David Scherer7aced172000-08-15 01:13:23 +0000237 if filename:
238 self.loadfile(filename)
239 else:
240 self.text.focus_set()
241 return "break"
242
Guido van Rossumc2f77dd2003-04-25 18:36:31 +0000243 eol = r"(\r\n)|\n|\r" # \r\n (Windows), \n (UNIX), or \r (Mac)
244 eol_re = re.compile(eol)
245 eol_convention = os.linesep # Default
246
David Scherer7aced172000-08-15 01:13:23 +0000247 def loadfile(self, filename):
248 try:
249 # open the file in binary mode so that we can handle
250 # end-of-line convention ourselves.
Terry Jan Reedyf9489432013-08-04 15:39:56 -0400251 with open(filename, 'rb') as f:
252 chars = f.read()
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400253 except IOError as msg:
David Scherer7aced172000-08-15 01:13:23 +0000254 tkMessageBox.showerror("I/O Error", str(msg), master=self.text)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000255 return False
David Scherer7aced172000-08-15 01:13:23 +0000256
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000257 chars = self.decode(chars)
David Scherer7aced172000-08-15 01:13:23 +0000258 # We now convert all end-of-lines to '\n's
Guido van Rossumc2f77dd2003-04-25 18:36:31 +0000259 firsteol = self.eol_re.search(chars)
260 if firsteol:
261 self.eol_convention = firsteol.group(0)
Martin v. Löwis249d50a2003-08-05 05:51:20 +0000262 if isinstance(self.eol_convention, unicode):
263 # Make sure it is an ASCII string
264 self.eol_convention = self.eol_convention.encode("ascii")
Guido van Rossumc2f77dd2003-04-25 18:36:31 +0000265 chars = self.eol_re.sub(r"\n", chars)
David Scherer7aced172000-08-15 01:13:23 +0000266
267 self.text.delete("1.0", "end")
268 self.set_filename(None)
269 self.text.insert("1.0", chars)
270 self.reset_undo()
271 self.set_filename(filename)
272 self.text.mark_set("insert", "1.0")
Ned Deilyd8b17232011-07-26 18:16:08 -0700273 self.text.yview("insert")
Chui Tey993e81a2002-11-04 03:11:10 +0000274 self.updaterecentfileslist(filename)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000275 return True
276
277 def decode(self, chars):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000278 """Create a Unicode string
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000279
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000280 If that fails, let Tcl try its best
281 """
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000282 # Check presence of a UTF-8 signature first
283 if chars.startswith(BOM_UTF8):
284 try:
285 chars = chars[3:].decode("utf-8")
286 except UnicodeError:
287 # has UTF-8 signature, but fails to decode...
288 return chars
289 else:
290 # Indicates that this file originally had a BOM
291 self.fileencoding = BOM_UTF8
292 return chars
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000293 # Next look for coding specification
294 try:
295 enc = coding_spec(chars)
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400296 except LookupError as name:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000297 tkMessageBox.showerror(
298 title="Error loading the file",
299 message="The encoding '%s' is not known to this Python "\
300 "installation. The file may not display correctly" % name,
301 master = self.text)
302 enc = None
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000303 if enc:
304 try:
305 return unicode(chars, enc)
306 except UnicodeError:
307 pass
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000308 # If it is ASCII, we need not to record anything
309 try:
310 return unicode(chars, 'ascii')
311 except UnicodeError:
312 pass
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000313 # Finally, try the locale's encoding. This is deprecated;
314 # the user should declare a non-ASCII encoding
315 try:
316 chars = unicode(chars, encoding)
317 self.fileencoding = encoding
318 except UnicodeError:
319 pass
320 return chars
David Scherer7aced172000-08-15 01:13:23 +0000321
322 def maybesave(self):
323 if self.get_saved():
324 return "yes"
325 message = "Do you want to save %s before closing?" % (
326 self.filename or "this untitled document")
Kurt B. Kaiserd82a8872011-05-12 21:18:47 -0400327 confirm = tkMessageBox.askyesnocancel(
328 title="Save On Close",
329 message=message,
330 default=tkMessageBox.YES,
331 master=self.text)
332 if confirm:
333 reply = "yes"
David Scherer7aced172000-08-15 01:13:23 +0000334 self.save(None)
335 if not self.get_saved():
336 reply = "cancel"
Kurt B. Kaiserd82a8872011-05-12 21:18:47 -0400337 elif confirm is None:
338 reply = "cancel"
339 else:
340 reply = "no"
David Scherer7aced172000-08-15 01:13:23 +0000341 self.text.focus_set()
342 return reply
343
344 def save(self, event):
345 if not self.filename:
346 self.save_as(event)
347 else:
348 if self.writefile(self.filename):
Kurt B. Kaiserd82a8872011-05-12 21:18:47 -0400349 self.set_saved(True)
Kurt B. Kaiserddeaf112003-03-04 04:42:04 +0000350 try:
351 self.editwin.store_file_breaks()
352 except AttributeError: # may be a PyShell
353 pass
David Scherer7aced172000-08-15 01:13:23 +0000354 self.text.focus_set()
355 return "break"
356
357 def save_as(self, event):
358 filename = self.asksavefile()
359 if filename:
360 if self.writefile(filename):
361 self.set_filename(filename)
362 self.set_saved(1)
Kurt B. Kaiserddeaf112003-03-04 04:42:04 +0000363 try:
364 self.editwin.store_file_breaks()
365 except AttributeError:
366 pass
David Scherer7aced172000-08-15 01:13:23 +0000367 self.text.focus_set()
Chui Tey993e81a2002-11-04 03:11:10 +0000368 self.updaterecentfileslist(filename)
David Scherer7aced172000-08-15 01:13:23 +0000369 return "break"
370
371 def save_a_copy(self, event):
372 filename = self.asksavefile()
373 if filename:
374 self.writefile(filename)
375 self.text.focus_set()
Chui Tey993e81a2002-11-04 03:11:10 +0000376 self.updaterecentfileslist(filename)
David Scherer7aced172000-08-15 01:13:23 +0000377 return "break"
378
379 def writefile(self, filename):
380 self.fixlastline()
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000381 chars = self.encode(self.text.get("1.0", "end-1c"))
Guido van Rossumc2f77dd2003-04-25 18:36:31 +0000382 if self.eol_convention != "\n":
383 chars = chars.replace("\n", self.eol_convention)
David Scherer7aced172000-08-15 01:13:23 +0000384 try:
Terry Jan Reedyf9489432013-08-04 15:39:56 -0400385 with open(filename, "wb") as f:
386 f.write(chars)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000387 return True
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400388 except IOError as msg:
David Scherer7aced172000-08-15 01:13:23 +0000389 tkMessageBox.showerror("I/O Error", str(msg),
390 master=self.text)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000391 return False
392
393 def encode(self, chars):
394 if isinstance(chars, types.StringType):
395 # This is either plain ASCII, or Tk was returning mixed-encoding
396 # text to us. Don't try to guess further.
397 return chars
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000398 # See whether there is anything non-ASCII in it.
399 # If not, no need to figure out the encoding.
400 try:
401 return chars.encode('ascii')
402 except UnicodeError:
403 pass
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000404 # If there is an encoding declared, try this first.
405 try:
406 enc = coding_spec(chars)
407 failed = None
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400408 except LookupError as msg:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000409 failed = msg
410 enc = None
411 if enc:
412 try:
413 return chars.encode(enc)
414 except UnicodeError:
415 failed = "Invalid encoding '%s'" % enc
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000416 if failed:
417 tkMessageBox.showerror(
418 "I/O Error",
419 "%s. Saving as UTF-8" % failed,
420 master = self.text)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000421 # If there was a UTF-8 signature, use that. This should not fail
422 if self.fileencoding == BOM_UTF8 or failed:
423 return BOM_UTF8 + chars.encode("utf-8")
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000424 # Try the original file encoding next, if any
425 if self.fileencoding:
426 try:
427 return chars.encode(self.fileencoding)
428 except UnicodeError:
429 tkMessageBox.showerror(
430 "I/O Error",
431 "Cannot save this as '%s' anymore. Saving as UTF-8" \
432 % self.fileencoding,
433 master = self.text)
434 return BOM_UTF8 + chars.encode("utf-8")
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000435 # Nothing was declared, and we had not determined an encoding
436 # on loading. Recommend an encoding line.
Kurt B. Kaiser47674012003-05-18 02:24:32 +0000437 config_encoding = idleConf.GetOption("main","EditorWindow",
438 "encoding")
439 if config_encoding == 'utf-8':
440 # User has requested that we save files as UTF-8
441 return BOM_UTF8 + chars.encode("utf-8")
442 ask_user = True
443 try:
444 chars = chars.encode(encoding)
445 enc = encoding
446 if config_encoding == 'locale':
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000447 ask_user = False
Kurt B. Kaiser47674012003-05-18 02:24:32 +0000448 except UnicodeError:
449 chars = BOM_UTF8 + chars.encode("utf-8")
450 enc = "utf-8"
451 if not ask_user:
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000452 return chars
Kurt B. Kaiser47674012003-05-18 02:24:32 +0000453 dialog = EncodingMessage(self.editwin.top, enc)
454 dialog.go()
455 if dialog.num == 1:
456 # User asked us to edit the file
457 encline = "# -*- coding: %s -*-\n" % enc
458 firstline = self.text.get("1.0", "2.0")
459 if firstline.startswith("#!"):
460 # Insert encoding after #! line
461 self.text.insert("2.0", encline)
462 else:
463 self.text.insert("1.0", encline)
464 return self.encode(self.text.get("1.0", "end-1c"))
465 return chars
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000466
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000467 def fixlastline(self):
468 c = self.text.get("end-2c")
469 if c != '\n':
470 self.text.insert("end-1c", "\n")
471
Steven M. Gava7981ce52002-06-11 04:45:34 +0000472 def print_window(self, event):
Kurt B. Kaiserd82a8872011-05-12 21:18:47 -0400473 confirm = tkMessageBox.askokcancel(
474 title="Print",
475 message="Print to Default Printer",
476 default=tkMessageBox.OK,
477 master=self.text)
478 if not confirm:
Kurt B. Kaiser60d58402007-10-28 19:03:59 +0000479 self.text.focus_set()
480 return "break"
Steven M. Gava7981ce52002-06-11 04:45:34 +0000481 tempfilename = None
Kurt B. Kaiser9067c8d2003-06-09 03:12:42 +0000482 saved = self.get_saved()
483 if saved:
Steven M. Gava7981ce52002-06-11 04:45:34 +0000484 filename = self.filename
Kurt B. Kaiser9067c8d2003-06-09 03:12:42 +0000485 # shell undo is reset after every prompt, looks saved, probably isn't
486 if not saved or filename is None:
Kurt B. Kaiser61e2c9a2003-06-14 17:56:25 +0000487 (tfd, tempfilename) = tempfile.mkstemp(prefix='IDLE_tmp_')
488 filename = tempfilename
489 os.close(tfd)
490 if not self.writefile(tempfilename):
Steven M. Gava7981ce52002-06-11 04:45:34 +0000491 os.unlink(tempfilename)
492 return "break"
Kurt B. Kaiserd82a8872011-05-12 21:18:47 -0400493 platform = os.name
494 printPlatform = True
Steven M. Gava7981ce52002-06-11 04:45:34 +0000495 if platform == 'posix': #posix platform
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000496 command = idleConf.GetOption('main','General',
497 'print-command-posix')
Steven M. Gava7981ce52002-06-11 04:45:34 +0000498 command = command + " 2>&1"
499 elif platform == 'nt': #win32 platform
500 command = idleConf.GetOption('main','General','print-command-win')
501 else: #no printing for this platform
Kurt B. Kaiserd82a8872011-05-12 21:18:47 -0400502 printPlatform = False
Steven M. Gava7981ce52002-06-11 04:45:34 +0000503 if printPlatform: #we can try to print for this platform
Serhiy Storchakaeebcb5f2013-01-12 18:12:27 +0200504 command = command % pipes.quote(filename)
Steven M. Gava7981ce52002-06-11 04:45:34 +0000505 pipe = os.popen(command, "r")
Kurt B. Kaiser9067c8d2003-06-09 03:12:42 +0000506 # things can get ugly on NT if there is no printer available.
Steven M. Gava7981ce52002-06-11 04:45:34 +0000507 output = pipe.read().strip()
508 status = pipe.close()
509 if status:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000510 output = "Printing failed (exit status 0x%x)\n" % \
511 status + output
Steven M. Gava7981ce52002-06-11 04:45:34 +0000512 if output:
513 output = "Printing command: %s\n" % repr(command) + output
514 tkMessageBox.showerror("Print status", output, master=self.text)
515 else: #no printing for this platform
Kurt B. Kaiserd82a8872011-05-12 21:18:47 -0400516 message = "Printing is not enabled for this platform: %s" % platform
Steven M. Gava7981ce52002-06-11 04:45:34 +0000517 tkMessageBox.showinfo("Print status", message, master=self.text)
Kurt B. Kaiser61e2c9a2003-06-14 17:56:25 +0000518 if tempfilename:
519 os.unlink(tempfilename)
Steven M. Gava7981ce52002-06-11 04:45:34 +0000520 return "break"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000521
David Scherer7aced172000-08-15 01:13:23 +0000522 opendialog = None
523 savedialog = None
524
525 filetypes = [
Terry Reedy277896a2010-11-23 06:44:05 +0000526 ("Python files", "*.py *.pyw", "TEXT"),
527 ("Text files", "*.txt", "TEXT"),
David Scherer7aced172000-08-15 01:13:23 +0000528 ("All files", "*"),
529 ]
530
Terry Jan Reedy57ac6232014-10-06 00:13:51 -0400531 defaultextension = '.py' if sys.platform == 'darwin' else ''
532
David Scherer7aced172000-08-15 01:13:23 +0000533 def askopenfile(self):
534 dir, base = self.defaultfilename("open")
535 if not self.opendialog:
536 self.opendialog = tkFileDialog.Open(master=self.text,
537 filetypes=self.filetypes)
Martin v. Löwis307021f2005-11-27 16:59:04 +0000538 filename = self.opendialog.show(initialdir=dir, initialfile=base)
539 if isinstance(filename, unicode):
540 filename = filename.encode(filesystemencoding)
541 return filename
David Scherer7aced172000-08-15 01:13:23 +0000542
543 def defaultfilename(self, mode="open"):
544 if self.filename:
545 return os.path.split(self.filename)
Kurt B. Kaiserd2f48612003-06-05 02:34:04 +0000546 elif self.dirname:
547 return self.dirname, ""
David Scherer7aced172000-08-15 01:13:23 +0000548 else:
549 try:
550 pwd = os.getcwd()
551 except os.error:
552 pwd = ""
553 return pwd, ""
554
555 def asksavefile(self):
556 dir, base = self.defaultfilename("save")
557 if not self.savedialog:
Terry Jan Reedy57ac6232014-10-06 00:13:51 -0400558 self.savedialog = tkFileDialog.SaveAs(
559 master=self.text,
560 filetypes=self.filetypes,
561 defaultextension=self.defaultextension)
Martin v. Löwis307021f2005-11-27 16:59:04 +0000562 filename = self.savedialog.show(initialdir=dir, initialfile=base)
563 if isinstance(filename, unicode):
564 filename = filename.encode(filesystemencoding)
565 return filename
David Scherer7aced172000-08-15 01:13:23 +0000566
Chui Tey993e81a2002-11-04 03:11:10 +0000567 def updaterecentfileslist(self,filename):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000568 "Update recent file list on all editor windows"
Kurt B. Kaisercf6f1b62004-04-11 03:16:07 +0000569 self.editwin.update_recent_files_list(filename)
Chui Tey993e81a2002-11-04 03:11:10 +0000570
Terry Jan Reedy62012fc2014-05-24 18:48:03 -0400571def _io_binding(parent):
David Scherer7aced172000-08-15 01:13:23 +0000572 root = Tk()
Terry Jan Reedy62012fc2014-05-24 18:48:03 -0400573 root.title("Test IOBinding")
574 width, height, x, y = list(map(int, re.split('[x+]', parent.geometry())))
575 root.geometry("+%d+%d"%(x, y + 150))
David Scherer7aced172000-08-15 01:13:23 +0000576 class MyEditWin:
577 def __init__(self, text):
578 self.text = text
579 self.flist = None
580 self.text.bind("<Control-o>", self.open)
581 self.text.bind("<Control-s>", self.save)
David Scherer7aced172000-08-15 01:13:23 +0000582 def get_saved(self): return 0
583 def set_saved(self, flag): pass
584 def reset_undo(self): pass
585 def open(self, event):
586 self.text.event_generate("<<open-window-from-file>>")
587 def save(self, event):
588 self.text.event_generate("<<save-window>>")
Terry Jan Reedy62012fc2014-05-24 18:48:03 -0400589
David Scherer7aced172000-08-15 01:13:23 +0000590 text = Text(root)
591 text.pack()
592 text.focus_set()
593 editwin = MyEditWin(text)
594 io = IOBinding(editwin)
David Scherer7aced172000-08-15 01:13:23 +0000595
596if __name__ == "__main__":
Terry Jan Reedy62012fc2014-05-24 18:48:03 -0400597 from idlelib.idle_test.htest import run
598 run(_io_binding)