blob: db6773f8a89dcfdd2f3312c5d29f403e1fe29316 [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
Serhiy Storchakaeebcb5f2013-01-12 18:12:27 +02009import pipes
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000010import sys
11import codecs
Steven M. Gava7981ce52002-06-11 04:45:34 +000012import tempfile
Georg Brandl6634bf22008-05-20 07:13:37 +000013import tkFileDialog
14import tkMessageBox
David Scherer7aced172000-08-15 01:13:23 +000015import re
Georg Brandl6634bf22008-05-20 07:13:37 +000016from Tkinter import *
17from SimpleDialog import SimpleDialog
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000018
Florent Xiclunad630c042010-04-02 07:24:52 +000019from idlelib.configHandler import idleConf
David Scherer7aced172000-08-15 01:13:23 +000020
Terry Jan Reedy57ac6232014-10-06 00:13:51 -040021from codecs import BOM_UTF8
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000022
23# Try setting the locale, so that we can find out
24# what encoding to use
25try:
26 import locale
27 locale.setlocale(locale.LC_CTYPE, "")
Kurt B. Kaiser188e25f2003-11-25 05:01:00 +000028except (ImportError, locale.Error):
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000029 pass
30
Martin v. Löwis307021f2005-11-27 16:59:04 +000031# Encoding for file names
32filesystemencoding = sys.getfilesystemencoding()
33
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000034encoding = "ascii"
35if sys.platform == 'win32':
36 # On Windows, we could use "mbcs". However, to give the user
37 # a portable encoding name, we need to find the code page
38 try:
39 encoding = locale.getdefaultlocale()[1]
40 codecs.lookup(encoding)
41 except LookupError:
42 pass
43else:
44 try:
45 # Different things can fail here: the locale module may not be
46 # loaded, it may not offer nl_langinfo, or CODESET, or the
47 # resulting codeset may be unknown to Python. We ignore all
48 # these problems, falling back to ASCII
49 encoding = locale.nl_langinfo(locale.CODESET)
Martin v. Löwisa9170c72004-08-12 13:14:52 +000050 if encoding is None or encoding is '':
Tony Lowndse555fc72002-09-23 01:01:20 +000051 # situation occurs on Mac OS X
52 encoding = 'ascii'
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000053 codecs.lookup(encoding)
54 except (NameError, AttributeError, LookupError):
55 # Try getdefaultlocale well: it parses environment variables,
56 # which may give a clue. Unfortunately, getdefaultlocale has
57 # bugs that can cause ValueError.
58 try:
59 encoding = locale.getdefaultlocale()[1]
Martin v. Löwisa9170c72004-08-12 13:14:52 +000060 if encoding is None or encoding is '':
Tony Lowndse555fc72002-09-23 01:01:20 +000061 # situation occurs on Mac OS X
62 encoding = 'ascii'
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000063 codecs.lookup(encoding)
64 except (ValueError, LookupError):
65 pass
66
67encoding = encoding.lower()
68
Serhiy Storchakae4818f62013-09-17 10:09:08 +030069coding_re = re.compile(r'^[ \t\f]*#.*coding[:=][ \t]*([-\w.]+)')
Serhiy Storchaka3eb554f2014-09-05 10:22:05 +030070blank_re = re.compile(r'^[ \t\f]*(?:[#\r\n]|$)')
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000071
Kurt B. Kaisera053f332003-05-10 00:49:56 +000072class EncodingMessage(SimpleDialog):
73 "Inform user that an encoding declaration is needed."
74 def __init__(self, master, enc):
75 self.should_edit = False
Kurt B. Kaiser47674012003-05-18 02:24:32 +000076
Kurt B. Kaisera053f332003-05-10 00:49:56 +000077 self.root = top = Toplevel(master)
78 top.bind("<Return>", self.return_event)
79 top.bind("<Escape>", self.do_ok)
80 top.protocol("WM_DELETE_WINDOW", self.wm_delete_window)
81 top.wm_title("I/O Warning")
82 top.wm_iconname("I/O Warning")
83 self.top = top
84
85 l1 = Label(top,
86 text="Non-ASCII found, yet no encoding declared. Add a line like")
87 l1.pack(side=TOP, anchor=W)
88 l2 = Entry(top, font="courier")
89 l2.insert(0, "# -*- coding: %s -*-" % enc)
90 # For some reason, the text is not selectable anymore if the
91 # widget is disabled.
92 # l2['state'] = DISABLED
93 l2.pack(side=TOP, anchor = W, fill=X)
94 l3 = Label(top, text="to your file\n"
95 "Choose OK to save this file as %s\n"
96 "Edit your general options to silence this warning" % enc)
97 l3.pack(side=TOP, anchor = W)
98
99 buttons = Frame(top)
100 buttons.pack(side=TOP, fill=X)
101 # Both return and cancel mean the same thing: do nothing
102 self.default = self.cancel = 0
103 b1 = Button(buttons, text="Ok", default="active",
104 command=self.do_ok)
105 b1.pack(side=LEFT, fill=BOTH, expand=1)
106 b2 = Button(buttons, text="Edit my file",
107 command=self.do_edit)
108 b2.pack(side=LEFT, fill=BOTH, expand=1)
Kurt B. Kaiser47674012003-05-18 02:24:32 +0000109
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000110 self._set_transient(master)
111
112 def do_ok(self):
113 self.done(0)
114
115 def do_edit(self):
116 self.done(1)
117
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000118def coding_spec(str):
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000119 """Return the encoding declaration according to PEP 263.
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000120
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000121 Raise LookupError if the encoding is declared but unknown.
122 """
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000123 # Only consider the first two lines
Serhiy Storchaka1c760ca2013-10-29 10:15:09 +0200124 lst = str.split("\n", 2)[:2]
Serhiy Storchakae787bce2013-09-17 00:00:46 +0300125 for line in lst:
126 match = coding_re.match(line)
127 if match is not None:
128 break
Serhiy Storchaka3eb554f2014-09-05 10:22:05 +0300129 if not blank_re.match(line):
130 return None
Serhiy Storchakae787bce2013-09-17 00:00:46 +0300131 else:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000132 return None
133 name = match.group(1)
134 # Check whether the encoding is known
135 import codecs
136 try:
137 codecs.lookup(name)
138 except LookupError:
139 # The standard encoding error does not indicate the encoding
140 raise LookupError, "Unknown encoding "+name
141 return name
David Scherer7aced172000-08-15 01:13:23 +0000142
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000143
David Scherer7aced172000-08-15 01:13:23 +0000144class IOBinding:
145
146 def __init__(self, editwin):
147 self.editwin = editwin
148 self.text = editwin.text
149 self.__id_open = self.text.bind("<<open-window-from-file>>", self.open)
150 self.__id_save = self.text.bind("<<save-window>>", self.save)
151 self.__id_saveas = self.text.bind("<<save-window-as-file>>",
152 self.save_as)
153 self.__id_savecopy = self.text.bind("<<save-copy-of-window-as-file>>",
154 self.save_a_copy)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000155 self.fileencoding = None
Steven M. Gava7981ce52002-06-11 04:45:34 +0000156 self.__id_print = self.text.bind("<<print-window>>", self.print_window)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000157
David Scherer7aced172000-08-15 01:13:23 +0000158 def close(self):
159 # Undo command bindings
160 self.text.unbind("<<open-window-from-file>>", self.__id_open)
161 self.text.unbind("<<save-window>>", self.__id_save)
162 self.text.unbind("<<save-window-as-file>>",self.__id_saveas)
163 self.text.unbind("<<save-copy-of-window-as-file>>", self.__id_savecopy)
Steven M. Gava7981ce52002-06-11 04:45:34 +0000164 self.text.unbind("<<print-window>>", self.__id_print)
David Scherer7aced172000-08-15 01:13:23 +0000165 # Break cycles
166 self.editwin = None
167 self.text = None
168 self.filename_change_hook = None
169
170 def get_saved(self):
171 return self.editwin.get_saved()
172
173 def set_saved(self, flag):
174 self.editwin.set_saved(flag)
175
176 def reset_undo(self):
177 self.editwin.reset_undo()
178
179 filename_change_hook = None
180
181 def set_filename_change_hook(self, hook):
182 self.filename_change_hook = hook
183
184 filename = None
Kurt B. Kaiserd2f48612003-06-05 02:34:04 +0000185 dirname = None
David Scherer7aced172000-08-15 01:13:23 +0000186
187 def set_filename(self, filename):
Kurt B. Kaiserd2f48612003-06-05 02:34:04 +0000188 if filename and os.path.isdir(filename):
189 self.filename = None
190 self.dirname = filename
191 else:
192 self.filename = filename
193 self.dirname = None
194 self.set_saved(1)
195 if self.filename_change_hook:
196 self.filename_change_hook()
David Scherer7aced172000-08-15 01:13:23 +0000197
Steven M. Gava1d46e402002-03-27 08:40:46 +0000198 def open(self, event=None, editFile=None):
Terry Jan Reedyeaa7e782012-05-26 20:33:32 -0400199 flist = self.editwin.flist
Terry Jan Reedyf0775132012-06-02 20:22:35 -0400200 # Save in case parent window is closed (ie, during askopenfile()).
Terry Jan Reedyeaa7e782012-05-26 20:33:32 -0400201 if flist:
Steven M. Gava1d46e402002-03-27 08:40:46 +0000202 if not editFile:
203 filename = self.askopenfile()
204 else:
205 filename=editFile
David Scherer7aced172000-08-15 01:13:23 +0000206 if filename:
Terry Jan Reedyf0775132012-06-02 20:22:35 -0400207 # If editFile is valid and already open, flist.open will
208 # shift focus to its existing window.
209 # If the current window exists and is a fresh unnamed,
210 # unmodified editor window (not an interpreter shell),
211 # pass self.loadfile to flist.open so it will load the file
212 # in the current window (if the file is not already open)
213 # instead of a new window.
214 if (self.editwin and
215 not getattr(self.editwin, 'interp', None) and
216 not self.filename and
217 self.get_saved()):
Terry Jan Reedyeaa7e782012-05-26 20:33:32 -0400218 flist.open(filename, self.loadfile)
David Scherer7aced172000-08-15 01:13:23 +0000219 else:
Terry Jan Reedyeaa7e782012-05-26 20:33:32 -0400220 flist.open(filename)
David Scherer7aced172000-08-15 01:13:23 +0000221 else:
Terry Jan Reedyeaa7e782012-05-26 20:33:32 -0400222 if self.text:
223 self.text.focus_set()
David Scherer7aced172000-08-15 01:13:23 +0000224 return "break"
Terry Jan Reedyf0775132012-06-02 20:22:35 -0400225
David Scherer7aced172000-08-15 01:13:23 +0000226 # Code for use outside IDLE:
227 if self.get_saved():
228 reply = self.maybesave()
229 if reply == "cancel":
230 self.text.focus_set()
231 return "break"
Steven M. Gava1d46e402002-03-27 08:40:46 +0000232 if not editFile:
233 filename = self.askopenfile()
234 else:
235 filename=editFile
David Scherer7aced172000-08-15 01:13:23 +0000236 if filename:
237 self.loadfile(filename)
238 else:
239 self.text.focus_set()
240 return "break"
241
Guido van Rossumc2f77dd2003-04-25 18:36:31 +0000242 eol = r"(\r\n)|\n|\r" # \r\n (Windows), \n (UNIX), or \r (Mac)
243 eol_re = re.compile(eol)
244 eol_convention = os.linesep # Default
245
David Scherer7aced172000-08-15 01:13:23 +0000246 def loadfile(self, filename):
247 try:
248 # open the file in binary mode so that we can handle
249 # end-of-line convention ourselves.
Terry Jan Reedyf9489432013-08-04 15:39:56 -0400250 with open(filename, 'rb') as f:
251 chars = f.read()
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400252 except IOError as msg:
David Scherer7aced172000-08-15 01:13:23 +0000253 tkMessageBox.showerror("I/O Error", str(msg), master=self.text)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000254 return False
David Scherer7aced172000-08-15 01:13:23 +0000255
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000256 chars = self.decode(chars)
David Scherer7aced172000-08-15 01:13:23 +0000257 # We now convert all end-of-lines to '\n's
Guido van Rossumc2f77dd2003-04-25 18:36:31 +0000258 firsteol = self.eol_re.search(chars)
259 if firsteol:
260 self.eol_convention = firsteol.group(0)
Martin v. Löwis249d50a2003-08-05 05:51:20 +0000261 if isinstance(self.eol_convention, unicode):
262 # Make sure it is an ASCII string
263 self.eol_convention = self.eol_convention.encode("ascii")
Guido van Rossumc2f77dd2003-04-25 18:36:31 +0000264 chars = self.eol_re.sub(r"\n", chars)
David Scherer7aced172000-08-15 01:13:23 +0000265
266 self.text.delete("1.0", "end")
267 self.set_filename(None)
268 self.text.insert("1.0", chars)
269 self.reset_undo()
270 self.set_filename(filename)
271 self.text.mark_set("insert", "1.0")
Ned Deilyd8b17232011-07-26 18:16:08 -0700272 self.text.yview("insert")
Chui Tey993e81a2002-11-04 03:11:10 +0000273 self.updaterecentfileslist(filename)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000274 return True
275
276 def decode(self, chars):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000277 """Create a Unicode string
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000278
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000279 If that fails, let Tcl try its best
280 """
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000281 # Check presence of a UTF-8 signature first
282 if chars.startswith(BOM_UTF8):
283 try:
284 chars = chars[3:].decode("utf-8")
285 except UnicodeError:
286 # has UTF-8 signature, but fails to decode...
287 return chars
288 else:
289 # Indicates that this file originally had a BOM
290 self.fileencoding = BOM_UTF8
291 return chars
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000292 # Next look for coding specification
293 try:
294 enc = coding_spec(chars)
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400295 except LookupError as name:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000296 tkMessageBox.showerror(
297 title="Error loading the file",
298 message="The encoding '%s' is not known to this Python "\
299 "installation. The file may not display correctly" % name,
300 master = self.text)
301 enc = None
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000302 if enc:
303 try:
304 return unicode(chars, enc)
305 except UnicodeError:
306 pass
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000307 # If it is ASCII, we need not to record anything
308 try:
309 return unicode(chars, 'ascii')
310 except UnicodeError:
311 pass
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000312 # Finally, try the locale's encoding. This is deprecated;
313 # the user should declare a non-ASCII encoding
314 try:
315 chars = unicode(chars, encoding)
316 self.fileencoding = encoding
317 except UnicodeError:
318 pass
319 return chars
David Scherer7aced172000-08-15 01:13:23 +0000320
321 def maybesave(self):
322 if self.get_saved():
323 return "yes"
324 message = "Do you want to save %s before closing?" % (
325 self.filename or "this untitled document")
Kurt B. Kaiserd82a8872011-05-12 21:18:47 -0400326 confirm = tkMessageBox.askyesnocancel(
327 title="Save On Close",
328 message=message,
329 default=tkMessageBox.YES,
330 master=self.text)
331 if confirm:
332 reply = "yes"
David Scherer7aced172000-08-15 01:13:23 +0000333 self.save(None)
334 if not self.get_saved():
335 reply = "cancel"
Kurt B. Kaiserd82a8872011-05-12 21:18:47 -0400336 elif confirm is None:
337 reply = "cancel"
338 else:
339 reply = "no"
David Scherer7aced172000-08-15 01:13:23 +0000340 self.text.focus_set()
341 return reply
342
343 def save(self, event):
344 if not self.filename:
345 self.save_as(event)
346 else:
347 if self.writefile(self.filename):
Kurt B. Kaiserd82a8872011-05-12 21:18:47 -0400348 self.set_saved(True)
Kurt B. Kaiserddeaf112003-03-04 04:42:04 +0000349 try:
350 self.editwin.store_file_breaks()
351 except AttributeError: # may be a PyShell
352 pass
David Scherer7aced172000-08-15 01:13:23 +0000353 self.text.focus_set()
354 return "break"
355
356 def save_as(self, event):
357 filename = self.asksavefile()
358 if filename:
359 if self.writefile(filename):
360 self.set_filename(filename)
361 self.set_saved(1)
Kurt B. Kaiserddeaf112003-03-04 04:42:04 +0000362 try:
363 self.editwin.store_file_breaks()
364 except AttributeError:
365 pass
David Scherer7aced172000-08-15 01:13:23 +0000366 self.text.focus_set()
Chui Tey993e81a2002-11-04 03:11:10 +0000367 self.updaterecentfileslist(filename)
David Scherer7aced172000-08-15 01:13:23 +0000368 return "break"
369
370 def save_a_copy(self, event):
371 filename = self.asksavefile()
372 if filename:
373 self.writefile(filename)
374 self.text.focus_set()
Chui Tey993e81a2002-11-04 03:11:10 +0000375 self.updaterecentfileslist(filename)
David Scherer7aced172000-08-15 01:13:23 +0000376 return "break"
377
378 def writefile(self, filename):
379 self.fixlastline()
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000380 chars = self.encode(self.text.get("1.0", "end-1c"))
Guido van Rossumc2f77dd2003-04-25 18:36:31 +0000381 if self.eol_convention != "\n":
382 chars = chars.replace("\n", self.eol_convention)
David Scherer7aced172000-08-15 01:13:23 +0000383 try:
Terry Jan Reedyf9489432013-08-04 15:39:56 -0400384 with open(filename, "wb") as f:
385 f.write(chars)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000386 return True
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400387 except IOError as msg:
David Scherer7aced172000-08-15 01:13:23 +0000388 tkMessageBox.showerror("I/O Error", str(msg),
389 master=self.text)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000390 return False
391
392 def encode(self, chars):
Terry Jan Reedyd8dc7492015-05-14 18:10:30 -0400393 if isinstance(chars, str):
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000394 # This is either plain ASCII, or Tk was returning mixed-encoding
395 # text to us. Don't try to guess further.
396 return chars
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000397 # See whether there is anything non-ASCII in it.
398 # If not, no need to figure out the encoding.
399 try:
400 return chars.encode('ascii')
401 except UnicodeError:
402 pass
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000403 # If there is an encoding declared, try this first.
404 try:
405 enc = coding_spec(chars)
406 failed = None
Terry Jan Reedy2b149862013-06-29 00:59:34 -0400407 except LookupError as msg:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000408 failed = msg
409 enc = None
410 if enc:
411 try:
412 return chars.encode(enc)
413 except UnicodeError:
414 failed = "Invalid encoding '%s'" % enc
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000415 if failed:
416 tkMessageBox.showerror(
417 "I/O Error",
418 "%s. Saving as UTF-8" % failed,
419 master = self.text)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000420 # If there was a UTF-8 signature, use that. This should not fail
421 if self.fileencoding == BOM_UTF8 or failed:
422 return BOM_UTF8 + chars.encode("utf-8")
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000423 # Try the original file encoding next, if any
424 if self.fileencoding:
425 try:
426 return chars.encode(self.fileencoding)
427 except UnicodeError:
428 tkMessageBox.showerror(
429 "I/O Error",
430 "Cannot save this as '%s' anymore. Saving as UTF-8" \
431 % self.fileencoding,
432 master = self.text)
433 return BOM_UTF8 + chars.encode("utf-8")
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000434 # Nothing was declared, and we had not determined an encoding
435 # on loading. Recommend an encoding line.
Kurt B. Kaiser47674012003-05-18 02:24:32 +0000436 config_encoding = idleConf.GetOption("main","EditorWindow",
437 "encoding")
438 if config_encoding == 'utf-8':
439 # User has requested that we save files as UTF-8
440 return BOM_UTF8 + chars.encode("utf-8")
441 ask_user = True
442 try:
443 chars = chars.encode(encoding)
444 enc = encoding
445 if config_encoding == 'locale':
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000446 ask_user = False
Kurt B. Kaiser47674012003-05-18 02:24:32 +0000447 except UnicodeError:
448 chars = BOM_UTF8 + chars.encode("utf-8")
449 enc = "utf-8"
450 if not ask_user:
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000451 return chars
Kurt B. Kaiser47674012003-05-18 02:24:32 +0000452 dialog = EncodingMessage(self.editwin.top, enc)
453 dialog.go()
454 if dialog.num == 1:
455 # User asked us to edit the file
456 encline = "# -*- coding: %s -*-\n" % enc
457 firstline = self.text.get("1.0", "2.0")
458 if firstline.startswith("#!"):
459 # Insert encoding after #! line
460 self.text.insert("2.0", encline)
461 else:
462 self.text.insert("1.0", encline)
463 return self.encode(self.text.get("1.0", "end-1c"))
464 return chars
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000465
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000466 def fixlastline(self):
467 c = self.text.get("end-2c")
468 if c != '\n':
469 self.text.insert("end-1c", "\n")
470
Steven M. Gava7981ce52002-06-11 04:45:34 +0000471 def print_window(self, event):
Kurt B. Kaiserd82a8872011-05-12 21:18:47 -0400472 confirm = tkMessageBox.askokcancel(
473 title="Print",
474 message="Print to Default Printer",
475 default=tkMessageBox.OK,
476 master=self.text)
477 if not confirm:
Kurt B. Kaiser60d58402007-10-28 19:03:59 +0000478 self.text.focus_set()
479 return "break"
Steven M. Gava7981ce52002-06-11 04:45:34 +0000480 tempfilename = None
Kurt B. Kaiser9067c8d2003-06-09 03:12:42 +0000481 saved = self.get_saved()
482 if saved:
Steven M. Gava7981ce52002-06-11 04:45:34 +0000483 filename = self.filename
Kurt B. Kaiser9067c8d2003-06-09 03:12:42 +0000484 # shell undo is reset after every prompt, looks saved, probably isn't
485 if not saved or filename is None:
Kurt B. Kaiser61e2c9a2003-06-14 17:56:25 +0000486 (tfd, tempfilename) = tempfile.mkstemp(prefix='IDLE_tmp_')
487 filename = tempfilename
488 os.close(tfd)
489 if not self.writefile(tempfilename):
Steven M. Gava7981ce52002-06-11 04:45:34 +0000490 os.unlink(tempfilename)
491 return "break"
Kurt B. Kaiserd82a8872011-05-12 21:18:47 -0400492 platform = os.name
493 printPlatform = True
Steven M. Gava7981ce52002-06-11 04:45:34 +0000494 if platform == 'posix': #posix platform
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000495 command = idleConf.GetOption('main','General',
496 'print-command-posix')
Steven M. Gava7981ce52002-06-11 04:45:34 +0000497 command = command + " 2>&1"
498 elif platform == 'nt': #win32 platform
499 command = idleConf.GetOption('main','General','print-command-win')
500 else: #no printing for this platform
Kurt B. Kaiserd82a8872011-05-12 21:18:47 -0400501 printPlatform = False
Steven M. Gava7981ce52002-06-11 04:45:34 +0000502 if printPlatform: #we can try to print for this platform
Serhiy Storchakaeebcb5f2013-01-12 18:12:27 +0200503 command = command % pipes.quote(filename)
Steven M. Gava7981ce52002-06-11 04:45:34 +0000504 pipe = os.popen(command, "r")
Kurt B. Kaiser9067c8d2003-06-09 03:12:42 +0000505 # things can get ugly on NT if there is no printer available.
Steven M. Gava7981ce52002-06-11 04:45:34 +0000506 output = pipe.read().strip()
507 status = pipe.close()
508 if status:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000509 output = "Printing failed (exit status 0x%x)\n" % \
510 status + output
Steven M. Gava7981ce52002-06-11 04:45:34 +0000511 if output:
512 output = "Printing command: %s\n" % repr(command) + output
513 tkMessageBox.showerror("Print status", output, master=self.text)
514 else: #no printing for this platform
Kurt B. Kaiserd82a8872011-05-12 21:18:47 -0400515 message = "Printing is not enabled for this platform: %s" % platform
Steven M. Gava7981ce52002-06-11 04:45:34 +0000516 tkMessageBox.showinfo("Print status", message, master=self.text)
Kurt B. Kaiser61e2c9a2003-06-14 17:56:25 +0000517 if tempfilename:
518 os.unlink(tempfilename)
Steven M. Gava7981ce52002-06-11 04:45:34 +0000519 return "break"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000520
David Scherer7aced172000-08-15 01:13:23 +0000521 opendialog = None
522 savedialog = None
523
524 filetypes = [
Terry Reedy277896a2010-11-23 06:44:05 +0000525 ("Python files", "*.py *.pyw", "TEXT"),
526 ("Text files", "*.txt", "TEXT"),
David Scherer7aced172000-08-15 01:13:23 +0000527 ("All files", "*"),
528 ]
529
Terry Jan Reedy57ac6232014-10-06 00:13:51 -0400530 defaultextension = '.py' if sys.platform == 'darwin' else ''
531
David Scherer7aced172000-08-15 01:13:23 +0000532 def askopenfile(self):
533 dir, base = self.defaultfilename("open")
534 if not self.opendialog:
535 self.opendialog = tkFileDialog.Open(master=self.text,
536 filetypes=self.filetypes)
Martin v. Löwis307021f2005-11-27 16:59:04 +0000537 filename = self.opendialog.show(initialdir=dir, initialfile=base)
538 if isinstance(filename, unicode):
539 filename = filename.encode(filesystemencoding)
540 return filename
David Scherer7aced172000-08-15 01:13:23 +0000541
542 def defaultfilename(self, mode="open"):
543 if self.filename:
544 return os.path.split(self.filename)
Kurt B. Kaiserd2f48612003-06-05 02:34:04 +0000545 elif self.dirname:
546 return self.dirname, ""
David Scherer7aced172000-08-15 01:13:23 +0000547 else:
548 try:
549 pwd = os.getcwd()
550 except os.error:
551 pwd = ""
552 return pwd, ""
553
554 def asksavefile(self):
555 dir, base = self.defaultfilename("save")
556 if not self.savedialog:
Terry Jan Reedy57ac6232014-10-06 00:13:51 -0400557 self.savedialog = tkFileDialog.SaveAs(
558 master=self.text,
559 filetypes=self.filetypes,
560 defaultextension=self.defaultextension)
Martin v. Löwis307021f2005-11-27 16:59:04 +0000561 filename = self.savedialog.show(initialdir=dir, initialfile=base)
562 if isinstance(filename, unicode):
563 filename = filename.encode(filesystemencoding)
564 return filename
David Scherer7aced172000-08-15 01:13:23 +0000565
Chui Tey993e81a2002-11-04 03:11:10 +0000566 def updaterecentfileslist(self,filename):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000567 "Update recent file list on all editor windows"
Kurt B. Kaisercf6f1b62004-04-11 03:16:07 +0000568 self.editwin.update_recent_files_list(filename)
Chui Tey993e81a2002-11-04 03:11:10 +0000569
Terry Jan Reedyd8dc7492015-05-14 18:10:30 -0400570def _io_binding(parent): # htest #
David Scherer7aced172000-08-15 01:13:23 +0000571 root = Tk()
Terry Jan Reedy62012fc2014-05-24 18:48:03 -0400572 root.title("Test IOBinding")
573 width, height, x, y = list(map(int, re.split('[x+]', parent.geometry())))
574 root.geometry("+%d+%d"%(x, y + 150))
David Scherer7aced172000-08-15 01:13:23 +0000575 class MyEditWin:
576 def __init__(self, text):
577 self.text = text
578 self.flist = None
579 self.text.bind("<Control-o>", self.open)
580 self.text.bind("<Control-s>", self.save)
David Scherer7aced172000-08-15 01:13:23 +0000581 def get_saved(self): return 0
582 def set_saved(self, flag): pass
583 def reset_undo(self): pass
584 def open(self, event):
585 self.text.event_generate("<<open-window-from-file>>")
586 def save(self, event):
587 self.text.event_generate("<<save-window>>")
Terry Jan Reedy62012fc2014-05-24 18:48:03 -0400588
David Scherer7aced172000-08-15 01:13:23 +0000589 text = Text(root)
590 text.pack()
591 text.focus_set()
592 editwin = MyEditWin(text)
Terry Jan Reedyd8dc7492015-05-14 18:10:30 -0400593 IOBinding(editwin)
David Scherer7aced172000-08-15 01:13:23 +0000594
595if __name__ == "__main__":
Terry Jan Reedy62012fc2014-05-24 18:48:03 -0400596 from idlelib.idle_test.htest import run
597 run(_io_binding)