def zoom_height(top): geom = top.wm_geometry() m = re.match(r"(\d+)x(\d+)\+(-?\d+)\+(-?\d+)", geom) if not m: top.bell() return width, height, x, y = map(int, m.groups()) newheight = top.winfo_screenheight() if sys.platform == 'win32': newy = 0 newheight = newheight - 72 elif macosxSupport.runningAsOSXApp(): # The '88' below is a magic number that avoids placing the bottom # of the window below the panel on my machine. I don't know how # to calculate the correct value for this with tkinter. newy = 22 newheight = newheight - newy - 88 else: #newy = 24 newy = 0 #newheight = newheight - 96 newheight = newheight - 88 if height >= newheight: newgeom = "" else: newgeom = "%dx%d+%d+%d" % (width, newheight, x, newy) top.wm_geometry(newgeom)
def __init__(self, editwin): self.editwin = editwin self.flist = self.editwin.flist self.root = self.editwin.root if macosxSupport.runningAsOSXApp(): self.editwin.text_frame.bind('<<run-module-event-2>>', self._run_module_event)
def delay(self): e = self.editwin m = e.rmenu_specs try: # This functionality in OutputWindow.py # requires the cursor to leave the input area in the shell. # IDLE should not do that. m.remove(('Go to file/line', '<<goto-file-line>>')) except: pass text = self.text if macosxSupport.runningAsOSXApp(): # Some OS X systems have only one mouse button, # so use control-click for pulldown menus there. # (Note, AquaTk defines <2> as the right button if # present and the Tk Text widget already binds <2>.) text.bind("<Control-Button-1>", self.right_menu_event) else: # Elsewhere, use right-click for pulldown menus. text.bind("<3>", self.right_menu_event) bmenu = [None] # breakpoint options for i in m: if 'breakpoint' in i[0].lower(): bmenu.append(i) else: self.rmenu_specs.append(i) self.rmenu_specs.extend(bmenu) self.make_rmenu()
def delay(self): e = self.editwin m = e.rmenu_specs try: # This functionality in OutputWindow.py # requires the cursor to leave the input area in the shell. # IDLE should not do that. m.remove(('Go to file/line', '<<goto-file-line>>')) except: pass text = self.text if macosxSupport.runningAsOSXApp(): # Some OS X systems have only one mouse button, # so use control-click for pulldown menus there. # (Note, AquaTk defines <2> as the right button if # present and the Tk Text widget already binds <2>.) text.bind("<Control-Button-1>",self.right_menu_event) else: # Elsewhere, use right-click for pulldown menus. text.bind("<3>",self.right_menu_event) bmenu = [None] # breakpoint options for i in m: if 'breakpoint' in i[0].lower(): bmenu.append(i) else: self.rmenu_specs.append(i) self.rmenu_specs.extend(bmenu) self.make_rmenu()
def main(runme=None): global flist, root, use_subprocess use_subprocess = True enable_shell = False enable_edit = False debug = False cmd = None script = None startup = False enable_shell = True args = [] if runme!=None: script = runme if os.path.isfile(script): pass else: print("Script not found: ", script) script = None use_subprocess = False # ehh? PyShell.shell_title = "durp" if script: sys.argv = [script] + args # start editor and/or shell windows: root = Tk(className="Idle") fixwordbreaks(root) root.withdraw() flist = PyShellFileList(root) macosxSupport.setupApp(root, flist) if enable_shell: shell = flist.open_shell() if not shell: return # couldn't open shell if macosxSupport.runningAsOSXApp() and flist.dict: # On OSX: when the user has double-clicked on a file that causes # IDLE to be launched the shell window will open just in front of # the file she wants to see. Lower the interpreter window when # there are open files. shell.top.lower() shell = flist.pyshell # handle remaining options: if script: shell.interp.runcommand("""if 1: import sys as _sys _sys.argv = %r del _sys \n""" % (sys.argv,)) shell.interp.prepend_syspath(script) shell.interp.execfile(script) root.mainloop() root.destroy()
def __init__(self, editwin): self.editwin = editwin # Provide instance variables referenced by Debugger # XXX This should be done differently self.flist = self.editwin.flist self.root = self.editwin.root if macosxSupport.runningAsOSXApp(): self.editwin.text_frame.bind('<<run-module-event-2>>', self._run_module_event)
def GetCurrentKeySet(self): result = self.GetKeySet(self.CurrentKeys()) if macosxSupport.runningAsOSXApp(): for k, v in result.items(): v2 = [x.replace('<Alt-', '<Option-') for x in v] if v != v2: result[k] = v2 return result
def set_status_bar(self): self.status_bar = self.MultiStatusBar(self.top) if macosxSupport.runningAsOSXApp(): self.status_bar.set_label('_padding1', ' ', side=RIGHT) self.status_bar.set_label('column', 'Col: ?', side=RIGHT) self.status_bar.set_label('line', 'Ln: ?', side=RIGHT) self.status_bar.pack(side=BOTTOM, fill=X) self.text.bind('<<set-line-and-column>>', self.set_line_and_column) self.text.event_add('<<set-line-and-column>>', '<KeyRelease>', '<ButtonRelease>') self.text.after_idle(self.set_line_and_column)
def __init__(self, master, flist, gui): if macosxSupport.runningAsOSXApp(): # At least on with the stock AquaTk version on OSX 10.4 you'll # get an shaking GUI that eventually kills IDLE if the width # argument is specified. ScrolledList.__init__(self, master) else: ScrolledList.__init__(self, master, width=80) self.flist = flist self.gui = gui self.stack = []
def createmenubar(self): mbar = self.menubar self.menudict = menudict = {} for name, label in self.menu_specs: underline, label = EditorWindow.prepstr(label) menudict[name] = menu = Menu(mbar, name=name) mbar.add_cascade(label=label, menu=menu, underline=underline) if macosxSupport.runningAsOSXApp(): # Insert the application menu menudict['application'] = menu = Menu(mbar, name='apple') mbar.add_cascade(label='IDLE', menu=menu)
def run_module_event(self, event): if macosxSupport.runningAsOSXApp(): # Tk-Cocoa in MacOSX is broken until at least # Tk 8.5.9, and without this rather # crude workaround IDLE would hang when a user # tries to run a module using the keyboard shortcut # (the menu item works fine). self.editwin.text_frame.after(200, lambda: self.editwin.text_frame.event_generate('<<run-module-event-2>>')) return 'break' else: return self._run_module_event(event)
def GetCurrentKeySet(self): result = self.GetKeySet(self.CurrentKeys()) if macosxSupport.runningAsOSXApp(): # We're using AquaTk, replace all keybingings that use the # Alt key by ones that use the Option key because the former # don't work reliably. for k, v in result.items(): v2 = [ x.replace('<Alt-', '<Option-') for x in v ] if v != v2: result[k] = v2 return result
def GetCurrentKeySet(self): result = self.GetKeySet(self.CurrentKeys()) if macosxSupport.runningAsOSXApp(): # We're using AquaTk, replace all keybingings that use the # Alt key by ones that use the Option key because the former # don't work reliably. for k, v in result.items(): v2 = [x.replace('<Alt-', '<Option-') for x in v] if v != v2: result[k] = v2 return result
def SetModifiersForPlatform(self): """Determine list of names of key modifiers for this platform. The names are used to build Tk bindings -- it doesn't matter if the keyboard has these keys, it matters if Tk understands them. The order is also important: key binding equality depends on it, so config-keys.def must use the same ordering. """ from idlelib import macosxSupport if macosxSupport.runningAsOSXApp(): self.modifiers = ['Shift', 'Control', 'Option', 'Command'] else: self.modifiers = ['Control', 'Alt', 'Shift'] self.modifier_label = {'Control': 'Ctrl'}
def SetModifiersForPlatform(self): """Determine list of names of key modifiers for this platform. The names are used to build Tk bindings -- it doesn't matter if the keyboard has these keys, it matters if Tk understands them. The order is also important: key binding equality depends on it, so config-keys.def must use the same ordering. """ from idlelib import macosxSupport if macosxSupport.runningAsOSXApp(): self.modifiers = ['Shift', 'Control', 'Option', 'Command'] else: self.modifiers = ['Control', 'Alt', 'Shift'] self.modifier_label = {'Control': 'Ctrl'} # short name
def initialise(): import sys global menudefs global default_keydefs if menudefs is not None: return menudefs = [ # underscore prefixes character to underscore #('file', [ # ]), ('edit', [ ('_Undo', '<<undo>>'), ('_Redo', '<<redo>>'), None, ('Cu_t', '<<cut>>'), ('_Copy', '<<copy>>'), ('_Paste', '<<paste>>'), ('Select _All', '<<select-all>>'), None, ('_Find...', '<<find>>'), ('Find A_gain', '<<find-again>>'), ('Find _Selection', '<<find-selection>>'), ('Find in Files...', '<<find-in-files>>'), ('R_eplace...', '<<replace>>'), ('Go to _Line', '<<goto-line>>'), ]), ('format', [ ('_Indent Region', '<<indent-region>>'), ('_Dedent Region', '<<dedent-region>>'), ('Comment _Out Region', '<<comment-region>>'), ('U_ncomment Region', '<<uncomment-region>>'), ('Tabify Region', '<<tabify-region>>'), ('Untabify Region', '<<untabify-region>>'), ('Toggle Tabs', '<<toggle-tabs>>'), ('New Indent Width', '<<change-indentwidth>>'), ]), ] if macosxSupport.runningAsOSXApp(): # Running as a proper MacOS application bundle. This block restructures # the menus a little to make them conform better to the HIG. quitItem = menudefs[0][1][-1] closeItem = menudefs[0][1][-2] default_keydefs = idleConf.GetCurrentKeySet()
def macosx_workaround(): # restore "Options" menu on MacOSX if not macosxSupport.runningAsOSXApp(): return def restore(menu_specs): c = [a for a,b in menu_specs] if "options" not in c: menu_specs.insert(-2, ("options", "Options")) import idlelib.EditorWindow restore(idlelib.EditorWindow.EditorWindow.menu_specs) import idlelib.PyShell restore(idlelib.PyShell.PyShell.menu_specs)
def get_accelerator(keydefs, eventname): keylist = keydefs.get(eventname) if not keylist or macosxSupport.runningAsOSXApp() and eventname in { '<<open-module>>', '<<goto-line>>', '<<change-indentwidth>>'}: return '' s = keylist[0] s = re.sub('-[a-z]\\b', lambda m: m.group().upper(), s) s = re.sub('\\b\\w+\\b', lambda m: keynames.get(m.group(), m.group()), s) s = re.sub('Key-', '', s) s = re.sub('Cancel', 'Ctrl-Break', s) s = re.sub('Control-', 'Ctrl-', s) s = re.sub('-', '+', s) s = re.sub('><', ' ', s) s = re.sub('<', '', s) s = re.sub('>', '', s) return s
def zoom_height(top): geom = top.wm_geometry() m = re.match('(\\d+)x(\\d+)\\+(-?\\d+)\\+(-?\\d+)', geom) if not m: top.bell() return width, height, x, y = map(int, m.groups()) newheight = top.winfo_screenheight() if sys.platform == 'win32': newy = 0 newheight = newheight - 72 elif macosxSupport.runningAsOSXApp(): newy = 22 newheight = newheight - newy - 88 else: newy = 0 newheight = newheight - 88 if height >= newheight: newgeom = '' else: newgeom = '%dx%d+%d+%d' % (width, newheight, x, newy) top.wm_geometry(newgeom)
class PyShell(OutputWindow): shell_title = 'Python Shell' ColorDelegator = ModifiedColorDelegator UndoDelegator = ModifiedUndoDelegator menu_specs = [ ('file', '_File'), ('edit', '_Edit'), ('debug', '_Debug'), ('options', '_Options'), ('windows', '_Windows'), ('help', '_Help')] if macosxSupport.runningAsOSXApp(): del menu_specs[-3] menu_specs[-2] = ('windows', '_Window') from idlelib.IdleHistory import History def __init__(self, flist=None): if use_subprocess: ms = self.menu_specs if ms[2][0] != 'shell': ms.insert(2, ('shell', 'She_ll')) self.interp = ModifiedInterpreter(self) if flist is None: root = Tk() fixwordbreaks(root) root.withdraw() flist = PyShellFileList(root) OutputWindow.__init__(self, flist, None, None) self.usetabs = True self.indentwidth = 8 self.context_use_ps1 = True text = self.text text.configure(wrap='char') text.bind('<<newline-and-indent>>', self.enter_callback) text.bind('<<plain-newline-and-indent>>', self.linefeed_callback) text.bind('<<interrupt-execution>>', self.cancel_callback) text.bind('<<end-of-file>>', self.eof_callback) text.bind('<<open-stack-viewer>>', self.open_stack_viewer) text.bind('<<toggle-debugger>>', self.toggle_debugger) text.bind('<<toggle-jit-stack-viewer>>', self.toggle_jit_stack_viewer) if use_subprocess: text.bind('<<view-restart>>', self.view_restart_mark) text.bind('<<restart-shell>>', self.restart_shell) self.save_stdout = sys.stdout self.save_stderr = sys.stderr self.save_stdin = sys.stdin from idlelib import IOBinding self.stdout = PseudoFile(self, 'stdout', IOBinding.encoding) self.stderr = PseudoFile(self, 'stderr', IOBinding.encoding) self.console = PseudoFile(self, 'console', IOBinding.encoding) if not use_subprocess: sys.stdout = self.stdout sys.stderr = self.stderr sys.stdin = self self.history = self.History(self.text) self.pollinterval = 50 return def get_standard_extension_names(self): return idleConf.GetExtensions(shell_only=True) reading = False executing = False canceled = False endoffile = False closing = False def set_warning_stream(self, stream): global warning_stream warning_stream = stream def get_warning_stream(self): return warning_stream def toggle_debugger(self, event=None): if self.executing: tkMessageBox.showerror("Don't debug now", 'You can only toggle the debugger when idle', master=self.text) self.set_debugger_indicator() return 'break' db = self.interp.getdebugger() if db: self.close_debugger() else: self.open_debugger() def set_debugger_indicator(self): db = self.interp.getdebugger() self.setvar('<<toggle-debugger>>', not not db) def toggle_jit_stack_viewer(self, event=None): pass def close_debugger(self): db = self.interp.getdebugger() if db: self.interp.setdebugger(None) db.close() if self.interp.rpcclt: RemoteDebugger.close_remote_debugger(self.interp.rpcclt) self.resetoutput() self.console.write('[DEBUG OFF]\n') sys.ps1 = '>>> ' self.showprompt() self.set_debugger_indicator() return def open_debugger(self): if self.interp.rpcclt: dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt, self) else: dbg_gui = Debugger.Debugger(self) self.interp.setdebugger(dbg_gui) dbg_gui.load_breakpoints() sys.ps1 = '[DEBUG ON]\n>>> ' self.showprompt() self.set_debugger_indicator() def beginexecuting(self): """Helper for ModifiedInterpreter""" self.resetoutput() self.executing = 1 def endexecuting(self): """Helper for ModifiedInterpreter""" self.executing = 0 self.canceled = 0 self.showprompt() def close(self): """Extend EditorWindow.close()""" if self.executing: response = tkMessageBox.askokcancel('Kill?', 'The program is still running!\n Do you want to kill it?', default='ok', parent=self.text) if response is False: return 'cancel' if self.reading: self.top.quit() self.canceled = True self.closing = True self.text.after(2 * self.pollinterval, self.close2) def close2(self): return EditorWindow.close(self) def _close(self): """Extend EditorWindow._close(), shut down debugger and execution server""" self.close_debugger() if use_subprocess: self.interp.kill_subprocess() sys.stdout = self.save_stdout sys.stderr = self.save_stderr sys.stdin = self.save_stdin self.interp = None self.console = None self.flist.pyshell = None self.history = None EditorWindow._close(self) return def ispythonsource(self, filename): """Override EditorWindow method: never remove the colorizer""" return True def short_title(self): return self.shell_title COPYRIGHT = 'Type "copyright", "credits" or "license()" for more information.' def begin(self): self.resetoutput() if use_subprocess: nosub = '' client = self.interp.start_subprocess() if not client: self.close() return False else: nosub = '==== No Subprocess ====' self.write('Python %s on %s\n%s\n%s' % ( sys.version, sys.platform, self.COPYRIGHT, nosub)) self.showprompt() import Tkinter Tkinter._default_root = None return True def readline(self): save = self.reading try: self.reading = 1 self.top.mainloop() finally: self.reading = save line = self.text.get('iomark', 'end-1c') if len(line) == 0: line = '\n' if isinstance(line, unicode): from idlelib import IOBinding try: line = line.encode(IOBinding.encoding) except UnicodeError: pass self.resetoutput() if self.canceled: self.canceled = 0 if not use_subprocess: raise KeyboardInterrupt if self.endoffile: self.endoffile = 0 line = '' return line def isatty(self): return True def cancel_callback(self, event=None): try: if self.text.compare('sel.first', '!=', 'sel.last'): return except: pass if not (self.executing or self.reading): self.resetoutput() self.interp.write('KeyboardInterrupt\n') self.showprompt() return 'break' self.endoffile = 0 self.canceled = 1 if self.executing and self.interp.rpcclt: if self.interp.getdebugger(): self.interp.restart_subprocess() else: self.interp.interrupt_subprocess() if self.reading: self.top.quit() return 'break' def eof_callback(self, event): if self.executing and not self.reading: return if not (self.text.compare('iomark', '==', 'insert') and self.text.compare('insert', '==', 'end-1c')): return if not self.executing: self.resetoutput() self.close() else: self.canceled = 0 self.endoffile = 1 self.top.quit() return 'break' def linefeed_callback(self, event): if self.reading: self.text.insert('insert', '\n') self.text.see('insert') else: self.newline_and_indent_event(event) return 'break' def enter_callback(self, event): if self.executing and not self.reading: return try: sel = self.text.get('sel.first', 'sel.last') if sel: if self.text.compare('sel.last', '<=', 'iomark'): self.recall(sel, event) return 'break' except: pass if self.text.compare('insert', '<', 'iomark linestart'): prev = self.text.tag_prevrange('stdin', 'insert') if prev and self.text.compare('insert', '<', prev[1]): self.recall(self.text.get(prev[0], prev[1]), event) return 'break' next = self.text.tag_nextrange('stdin', 'insert') if next and self.text.compare('insert lineend', '>=', next[0]): self.recall(self.text.get(next[0], next[1]), event) return 'break' indices = self.text.tag_nextrange('console', 'insert linestart') if indices and self.text.compare(indices[0], '<=', 'insert linestart'): self.recall(self.text.get(indices[1], 'insert lineend'), event) else: self.recall(self.text.get('insert linestart', 'insert lineend'), event) return 'break' if self.text.compare('insert', '<', 'iomark'): self.text.mark_set('insert', 'iomark') s = self.text.get('insert', 'end-1c') if s and not s.strip(): self.text.delete('insert', 'end-1c') if self.text.compare('insert', '<', 'end-1c linestart'): self.newline_and_indent_event(event) return 'break' self.text.mark_set('insert', 'end-1c') if self.reading: self.text.insert('insert', '\n') self.text.see('insert') else: self.newline_and_indent_event(event) self.text.tag_add('stdin', 'iomark', 'end-1c') self.text.update_idletasks() if self.reading: self.top.quit() else: self.runit() return 'break' def recall(self, s, event): s = re.sub('^\\s*\\n', '', s) s = re.sub('\\n\\s*$', '', s) lines = s.split('\n') self.text.undo_block_start() try: self.text.tag_remove('sel', '1.0', 'end') self.text.mark_set('insert', 'end-1c') prefix = self.text.get('insert linestart', 'insert') if prefix.rstrip().endswith(':'): self.newline_and_indent_event(event) prefix = self.text.get('insert linestart', 'insert') self.text.insert('insert', lines[0].strip()) if len(lines) > 1: orig_base_indent = re.search('^([ \\t]*)', lines[0]).group(0) new_base_indent = re.search('^([ \\t]*)', prefix).group(0) for line in lines[1:]: if line.startswith(orig_base_indent): line = new_base_indent + line[len(orig_base_indent):] self.text.insert('insert', '\n' + line.rstrip()) finally: self.text.see('insert') self.text.undo_block_stop() def runit(self): line = self.text.get('iomark', 'end-1c') i = len(line) while i > 0 and line[i - 1] in ' \t': i = i - 1 if i > 0 and line[i - 1] == '\n': i = i - 1 while i > 0 and line[i - 1] in ' \t': i = i - 1 line = line[:i] more = self.interp.runsource(line) def open_stack_viewer(self, event=None): if self.interp.rpcclt: return self.interp.remote_stack_viewer() try: sys.last_traceback except: tkMessageBox.showerror('No stack trace', 'There is no stack trace yet.\n(sys.last_traceback is not defined)', master=self.text) return from idlelib.StackViewer import StackBrowser sv = StackBrowser(self.root, self.flist) def view_restart_mark(self, event=None): self.text.see('iomark') self.text.see('restart') def restart_shell(self, event=None): self.interp.restart_subprocess() def showprompt(self): self.resetoutput() try: s = str(sys.ps1) except: s = '' self.console.write(s) self.text.mark_set('insert', 'end-1c') self.set_line_and_column() self.io.reset_undo() def resetoutput(self): source = self.text.get('iomark', 'end-1c') if self.history: self.history.history_store(source) if self.text.get('end-2c') != '\n': self.text.insert('end-1c', '\n') self.text.mark_set('iomark', 'end-1c') self.set_line_and_column() sys.stdout.softspace = 0 def write(self, s, tags=()): try: self.text.mark_gravity('iomark', 'right') OutputWindow.write(self, s, tags, 'iomark') self.text.mark_gravity('iomark', 'left') except: pass if self.canceled: self.canceled = 0 if not use_subprocess: raise KeyboardInterrupt
root.withdraw() flist = PyShellFileList(root) macosxSupport.setupApp(root, flist) if enable_edit: if not (cmd or script): for filename in args: flist.open(filename) if not args: flist.new() if enable_shell: shell = flist.open_shell() if not shell: return # couldn't open shell if macosxSupport.runningAsOSXApp() and flist.dict: # On OSX: when the user has double-clicked on a file that causes # IDLE to be launched the shell window will open just in front of # the file she wants to see. Lower the interpreter window when # there are open files. shell.top.lower() shell = flist.pyshell # handle remaining options: if debug: shell.open_debugger() if startup: filename = os.environ.get("IDLESTARTUP") or os.environ.get("PYTHONSTARTUP") if filename and os.path.isfile(filename): shell.interp.execfile(filename) if shell and cmd or script:
MC_MOTION = 17 MC_MOUSEWHEEL = 18 MC_PROPERTY = 19 MC_REPARENT = 20 MC_UNMAP = 21 MC_VISIBILITY = 22 # the modifier state constants, which define the meaning of mc_state MC_SHIFT = 1 << 0 MC_CONTROL = 1 << 2 MC_ALT = 1 << 3 MC_META = 1 << 5 MC_OPTION = 1 << 6 MC_COMMAND = 1 << 7 # define the list of modifiers, to be used in complex event types. if macosxSupport.runningAsOSXApp(): _modifiers = (("Shift", ), ("Control", ), ("Option", ), ("Command", )) _modifier_masks = (MC_SHIFT, MC_CONTROL, MC_OPTION, MC_COMMAND) else: _modifiers = (("Control", ), ("Alt", ), ("Shift", ), ("Meta", "M")) _modifier_masks = (MC_CONTROL, MC_ALT, MC_SHIFT, MC_META) # a dictionary to map a modifier name into its number _modifier_names = dict([(name, number) for number in range(len(_modifiers)) for name in _modifiers[number]]) # A binder is a class which binds functions to one type of event. It has two # methods: bind and unbind, which get a function and a parsed sequence, as # returned by _parse_sequence(). There are two types of binders: # _SimpleBinder handles event types with no modifiers and no detail. # No Python functions are called when no events are binded.
def __init__(self, flist=None, filename=None, key=None, root=None): if EditorWindow.help_url is None: dochome = os.path.join(sys.prefix, 'Doc', 'index.html') if sys.platform.count('linux'): pyver = 'python-docs-' + '%s.%s.%s' % sys.version_info[:3] if os.path.isdir('/var/www/html/python/'): dochome = '/var/www/html/python/index.html' else: basepath = '/usr/share/doc/' dochome = os.path.join(basepath, pyver, 'Doc', 'index.html') elif sys.platform[:3] == 'win': chmfile = os.path.join(sys.prefix, 'Doc', 'Python%s.chm' % _sphinx_version()) if os.path.isfile(chmfile): dochome = chmfile elif macosxSupport.runningAsOSXApp(): dochome = os.path.join(sys.prefix, 'Resources/English.lproj/Documentation/index.html') dochome = os.path.normpath(dochome) if os.path.isfile(dochome): EditorWindow.help_url = dochome if sys.platform == 'darwin': EditorWindow.help_url = 'file://' + EditorWindow.help_url else: EditorWindow.help_url = 'http://docs.python.org/%d.%d' % sys.version_info[:2] currentTheme = idleConf.CurrentTheme() self.flist = flist root = root or flist.root self.root = root try: sys.ps1 except AttributeError: sys.ps1 = '>>> ' self.menubar = Menu(root) self.top = top = WindowList.ListedToplevel(root, menu=self.menubar) if flist: self.tkinter_vars = flist.vars self.top.instance_dict = flist.inversedict else: self.tkinter_vars = {} self.top.instance_dict = {} self.recent_files_path = os.path.join(idleConf.GetUserCfgDir(), 'recent-files.lst') self.text_frame = text_frame = Frame(top) self.vbar = vbar = Scrollbar(text_frame, name='vbar') self.width = idleConf.GetOption('main', 'EditorWindow', 'width') text_options = {'name': 'text', 'padx': 5, 'wrap': 'none', 'width': self.width, 'height': idleConf.GetOption('main', 'EditorWindow', 'height') } if TkVersion >= 8.5: text_options['tabstyle'] = 'wordprocessor' self.text = text = MultiCallCreator(Text)(text_frame, **text_options) self.top.focused_widget = self.text self.createmenubar() self.apply_bindings() self.top.protocol('WM_DELETE_WINDOW', self.close) self.top.bind('<<close-window>>', self.close_event) if macosxSupport.runningAsOSXApp(): text.bind('<<close-window>>', self.close_event) text.bind('<Control-Button-1>', self.right_menu_event) else: text.bind('<3>', self.right_menu_event) text.bind('<<cut>>', self.cut) text.bind('<<copy>>', self.copy) text.bind('<<paste>>', self.paste) text.bind('<<center-insert>>', self.center_insert_event) text.bind('<<help>>', self.help_dialog) text.bind('<<python-docs>>', self.python_docs) text.bind('<<about-idle>>', self.about_dialog) text.bind('<<open-config-dialog>>', self.config_dialog) text.bind('<<open-module>>', self.open_module) text.bind('<<do-nothing>>', lambda event: 'break') text.bind('<<select-all>>', self.select_all) text.bind('<<remove-selection>>', self.remove_selection) text.bind('<<find>>', self.find_event) text.bind('<<find-again>>', self.find_again_event) text.bind('<<find-in-files>>', self.find_in_files_event) text.bind('<<find-selection>>', self.find_selection_event) text.bind('<<replace>>', self.replace_event) text.bind('<<goto-line>>', self.goto_line_event) text.bind('<<smart-backspace>>', self.smart_backspace_event) text.bind('<<newline-and-indent>>', self.newline_and_indent_event) text.bind('<<smart-indent>>', self.smart_indent_event) text.bind('<<indent-region>>', self.indent_region_event) text.bind('<<dedent-region>>', self.dedent_region_event) text.bind('<<comment-region>>', self.comment_region_event) text.bind('<<uncomment-region>>', self.uncomment_region_event) text.bind('<<tabify-region>>', self.tabify_region_event) text.bind('<<untabify-region>>', self.untabify_region_event) text.bind('<<toggle-tabs>>', self.toggle_tabs_event) text.bind('<<change-indentwidth>>', self.change_indentwidth_event) text.bind('<Left>', self.move_at_edge_if_selection(0)) text.bind('<Right>', self.move_at_edge_if_selection(1)) text.bind('<<del-word-left>>', self.del_word_left) text.bind('<<del-word-right>>', self.del_word_right) text.bind('<<beginning-of-line>>', self.home_callback) if flist: flist.inversedict[self] = key if key: flist.dict[key] = self text.bind('<<open-new-window>>', self.new_callback) text.bind('<<close-all-windows>>', self.flist.close_all_callback) text.bind('<<open-class-browser>>', self.open_class_browser) text.bind('<<open-path-browser>>', self.open_path_browser) self.set_status_bar() vbar['command'] = text.yview vbar.pack(side=RIGHT, fill=Y) text['yscrollcommand'] = vbar.set fontWeight = 'normal' if idleConf.GetOption('main', 'EditorWindow', 'font-bold', type='bool'): fontWeight = 'bold' text.config(font=(idleConf.GetOption('main', 'EditorWindow', 'font'), idleConf.GetOption('main', 'EditorWindow', 'font-size'), fontWeight)) text_frame.pack(side=LEFT, fill=BOTH, expand=1) text.pack(side=TOP, fill=BOTH, expand=1) text.focus_set() usespaces = idleConf.GetOption('main', 'Indent', 'use-spaces', type='bool') self.usetabs = not usespaces self.tabwidth = 8 self.indentwidth = self.tabwidth self.set_notabs_indentwidth() self.context_use_ps1 = False self.num_context_lines = (50, 500, 5000000) self.per = per = self.Percolator(text) self.undo = undo = self.UndoDelegator() per.insertfilter(undo) text.undo_block_start = undo.undo_block_start text.undo_block_stop = undo.undo_block_stop undo.set_saved_change_hook(self.saved_change_hook) self.io = io = self.IOBinding(self) io.set_filename_change_hook(self.filename_change_hook) self.recent_files_menu = Menu(self.menubar) self.menudict['file'].insert_cascade(3, label='Recent Files', underline=0, menu=self.recent_files_menu) self.update_recent_files_list() self.color = None if filename: if os.path.exists(filename) and not os.path.isdir(filename): io.loadfile(filename) else: io.set_filename(filename) self.ResetColorizer() self.saved_change_hook() self.set_indentation_params(self.ispythonsource(filename)) self.load_extensions() menu = self.menudict.get('windows') if menu: end = menu.index('end') if end is None: end = -1 if end >= 0: menu.add_separator() end = end + 1 self.wmenu_end = end WindowList.register_callback(self.postwindowsmenu) self.askyesno = tkMessageBox.askyesno self.askinteger = tkSimpleDialog.askinteger self.showerror = tkMessageBox.showerror return
class PyShell(OutputWindow): shell_title = "Python Shell" # Override classes ColorDelegator = ModifiedColorDelegator UndoDelegator = ModifiedUndoDelegator # Override menus menu_specs = [ ("file", "_File"), ("edit", "_Edit"), ("debug", "_Debug"), ("options", "_Options"), ("windows", "_Windows"), ("help", "_Help"), ] if macosxSupport.runningAsOSXApp(): del menu_specs[-3] menu_specs[-2] = ("windows", "_Window") # New classes from idlelib.IdleHistory import History def __init__(self, flist=None): if use_subprocess: ms = self.menu_specs if ms[2][0] != "shell": ms.insert(2, ("shell", "She_ll")) self.interp = ModifiedInterpreter(self) if flist is None: root = Tk() fixwordbreaks(root) root.withdraw() flist = PyShellFileList(root) # OutputWindow.__init__(self, flist, None, None) # ## self.config(usetabs=1, indentwidth=8, context_use_ps1=1) self.usetabs = True # indentwidth must be 8 when using tabs. See note in EditorWindow: self.indentwidth = 8 self.context_use_ps1 = True # text = self.text text.configure(wrap="char") text.bind("<<newline-and-indent>>", self.enter_callback) text.bind("<<plain-newline-and-indent>>", self.linefeed_callback) text.bind("<<interrupt-execution>>", self.cancel_callback) text.bind("<<end-of-file>>", self.eof_callback) text.bind("<<open-stack-viewer>>", self.open_stack_viewer) text.bind("<<toggle-debugger>>", self.toggle_debugger) text.bind("<<toggle-jit-stack-viewer>>", self.toggle_jit_stack_viewer) self.color = color = self.ColorDelegator() self.per.insertfilter(color) if use_subprocess: text.bind("<<view-restart>>", self.view_restart_mark) text.bind("<<restart-shell>>", self.restart_shell) # self.save_stdout = sys.stdout self.save_stderr = sys.stderr self.save_stdin = sys.stdin from idlelib import IOBinding self.stdout = PseudoFile(self, "stdout", IOBinding.encoding) self.stderr = PseudoFile(self, "stderr", IOBinding.encoding) self.console = PseudoFile(self, "console", IOBinding.encoding) if not use_subprocess: sys.stdout = self.stdout sys.stderr = self.stderr sys.stdin = self try: # page help() text to shell. import pydoc # import must be done here to capture i/o rebinding. # XXX KBK 27Dec07 use a textView someday, but must work w/o subproc pydoc.pager = pydoc.plainpager except: sys.stderr = sys.__stderr__ raise # self.history = self.History(self.text) # self.pollinterval = 50 # millisec def get_standard_extension_names(self): return idleConf.GetExtensions(shell_only=True) reading = False executing = False canceled = False endoffile = False closing = False def set_warning_stream(self, stream): global warning_stream warning_stream = stream def get_warning_stream(self): return warning_stream def toggle_debugger(self, event=None): if self.executing: tkMessageBox.showerror("Don't debug now", "You can only toggle the debugger when idle", master=self.text) self.set_debugger_indicator() return "break" else: db = self.interp.getdebugger() if db: self.close_debugger() else: self.open_debugger() def set_debugger_indicator(self): db = self.interp.getdebugger() self.setvar("<<toggle-debugger>>", not not db) def toggle_jit_stack_viewer(self, event=None): pass # All we need is the variable def close_debugger(self): db = self.interp.getdebugger() if db: self.interp.setdebugger(None) db.close() if self.interp.rpcclt: RemoteDebugger.close_remote_debugger(self.interp.rpcclt) self.resetoutput() self.console.write("[DEBUG OFF]\n") sys.ps1 = ">>> " self.showprompt() self.set_debugger_indicator() def open_debugger(self): if self.interp.rpcclt: dbg_gui = RemoteDebugger.start_remote_debugger(self.interp.rpcclt, self) else: dbg_gui = Debugger.Debugger(self) self.interp.setdebugger(dbg_gui) dbg_gui.load_breakpoints() sys.ps1 = "[DEBUG ON]\n>>> " self.showprompt() self.set_debugger_indicator() def beginexecuting(self): "Helper for ModifiedInterpreter" self.resetoutput() self.executing = 1 def endexecuting(self): "Helper for ModifiedInterpreter" self.executing = 0 self.canceled = 0 self.showprompt() def close(self): "Extend EditorWindow.close()" if self.executing: response = tkMessageBox.askokcancel( "Kill?", "The program is still running!\n Do you want to kill it?", default="ok", parent=self.text) if response is False: return "cancel" if self.reading: self.top.quit() self.canceled = True self.closing = True # Wait for poll_subprocess() rescheduling to stop self.text.after(2 * self.pollinterval, self.close2) def close2(self): return EditorWindow.close(self) def _close(self): "Extend EditorWindow._close(), shut down debugger and execution server" self.close_debugger() if use_subprocess: self.interp.kill_subprocess() # Restore std streams sys.stdout = self.save_stdout sys.stderr = self.save_stderr sys.stdin = self.save_stdin # Break cycles self.interp = None self.console = None self.flist.pyshell = None self.history = None EditorWindow._close(self) def ispythonsource(self, filename): "Override EditorWindow method: never remove the colorizer" return True def short_title(self): return self.shell_title COPYRIGHT = \ 'Type "copyright", "credits" or "license()" for more information.' def begin(self): self.text.mark_set("iomark", "insert") self.resetoutput() if use_subprocess: nosub = '' client = self.interp.start_subprocess() if not client: self.close() return False else: nosub = "==== No Subprocess ====" self.write("Python %s on %s\n%s\n%s" % (sys.version, sys.platform, self.COPYRIGHT, nosub)) self.showprompt() import tkinter tkinter._default_root = None # 03Jan04 KBK What's this? return True def readline(self): save = self.reading try: self.reading = 1 self.top.mainloop() # nested mainloop() finally: self.reading = save line = self.text.get("iomark", "end-1c") if len(line) == 0: # may be EOF if we quit our mainloop with Ctrl-C line = "\n" self.resetoutput() if self.canceled: self.canceled = 0 if not use_subprocess: raise KeyboardInterrupt if self.endoffile: self.endoffile = 0 line = "" return line def isatty(self): return True def cancel_callback(self, event=None): try: if self.text.compare("sel.first", "!=", "sel.last"): return # Active selection -- always use default binding except: pass if not (self.executing or self.reading): self.resetoutput() self.interp.write("KeyboardInterrupt\n") self.showprompt() return "break" self.endoffile = 0 self.canceled = 1 if (self.executing and self.interp.rpcclt): if self.interp.getdebugger(): self.interp.restart_subprocess() else: self.interp.interrupt_subprocess() if self.reading: self.top.quit() # exit the nested mainloop() in readline() return "break" def eof_callback(self, event): if self.executing and not self.reading: return # Let the default binding (delete next char) take over if not (self.text.compare("iomark", "==", "insert") and self.text.compare("insert", "==", "end-1c")): return # Let the default binding (delete next char) take over if not self.executing: self.resetoutput() self.close() else: self.canceled = 0 self.endoffile = 1 self.top.quit() return "break" def linefeed_callback(self, event): # Insert a linefeed without entering anything (still autoindented) if self.reading: self.text.insert("insert", "\n") self.text.see("insert") else: self.newline_and_indent_event(event) return "break" def enter_callback(self, event): if self.executing and not self.reading: return # Let the default binding (insert '\n') take over # If some text is selected, recall the selection # (but only if this before the I/O mark) try: sel = self.text.get("sel.first", "sel.last") if sel: if self.text.compare("sel.last", "<=", "iomark"): self.recall(sel, event) return "break" except: pass # If we're strictly before the line containing iomark, recall # the current line, less a leading prompt, less leading or # trailing whitespace if self.text.compare("insert", "<", "iomark linestart"): # Check if there's a relevant stdin range -- if so, use it prev = self.text.tag_prevrange("stdin", "insert") if prev and self.text.compare("insert", "<", prev[1]): self.recall(self.text.get(prev[0], prev[1]), event) return "break" next = self.text.tag_nextrange("stdin", "insert") if next and self.text.compare("insert lineend", ">=", next[0]): self.recall(self.text.get(next[0], next[1]), event) return "break" # No stdin mark -- just get the current line, less any prompt indices = self.text.tag_nextrange("console", "insert linestart") if indices and \ self.text.compare(indices[0], "<=", "insert linestart"): self.recall(self.text.get(indices[1], "insert lineend"), event) else: self.recall(self.text.get("insert linestart", "insert lineend"), event) return "break" # If we're between the beginning of the line and the iomark, i.e. # in the prompt area, move to the end of the prompt if self.text.compare("insert", "<", "iomark"): self.text.mark_set("insert", "iomark") # If we're in the current input and there's only whitespace # beyond the cursor, erase that whitespace first s = self.text.get("insert", "end-1c") if s and not s.strip(): self.text.delete("insert", "end-1c") # If we're in the current input before its last line, # insert a newline right at the insert point if self.text.compare("insert", "<", "end-1c linestart"): self.newline_and_indent_event(event) return "break" # We're in the last line; append a newline and submit it self.text.mark_set("insert", "end-1c") if self.reading: self.text.insert("insert", "\n") self.text.see("insert") else: self.newline_and_indent_event(event) self.text.tag_add("stdin", "iomark", "end-1c") self.text.update_idletasks() if self.reading: self.top.quit() # Break out of recursive mainloop() else: self.runit() return "break" def recall(self, s, event): # remove leading and trailing empty or whitespace lines s = re.sub(r'^\s*\n', '' , s) s = re.sub(r'\n\s*$', '', s) lines = s.split('\n') self.text.undo_block_start() try: self.text.tag_remove("sel", "1.0", "end") self.text.mark_set("insert", "end-1c") prefix = self.text.get("insert linestart", "insert") if prefix.rstrip().endswith(':'): self.newline_and_indent_event(event) prefix = self.text.get("insert linestart", "insert") self.text.insert("insert", lines[0].strip()) if len(lines) > 1: orig_base_indent = re.search(r'^([ \t]*)', lines[0]).group(0) new_base_indent = re.search(r'^([ \t]*)', prefix).group(0) for line in lines[1:]: if line.startswith(orig_base_indent): # replace orig base indentation with new indentation line = new_base_indent + line[len(orig_base_indent):] self.text.insert('insert', '\n'+line.rstrip()) finally: self.text.see("insert") self.text.undo_block_stop() def runit(self): line = self.text.get("iomark", "end-1c") # Strip off last newline and surrounding whitespace. # (To allow you to hit return twice to end a statement.) i = len(line) while i > 0 and line[i-1] in " \t": i = i-1 if i > 0 and line[i-1] == "\n": i = i-1 while i > 0 and line[i-1] in " \t": i = i-1 line = line[:i] more = self.interp.runsource(line) def open_stack_viewer(self, event=None): if self.interp.rpcclt: return self.interp.remote_stack_viewer() try: sys.last_traceback except: tkMessageBox.showerror("No stack trace", "There is no stack trace yet.\n" "(sys.last_traceback is not defined)", master=self.text) return from idlelib.StackViewer import StackBrowser sv = StackBrowser(self.root, self.flist) def view_restart_mark(self, event=None): self.text.see("iomark") self.text.see("restart") def restart_shell(self, event=None): self.interp.restart_subprocess() def showprompt(self): self.resetoutput() try: s = str(sys.ps1) except: s = "" self.console.write(s) self.text.mark_set("insert", "end-1c") self.set_line_and_column() self.io.reset_undo() def resetoutput(self): source = self.text.get("iomark", "end-1c") if self.history: self.history.history_store(source) if self.text.get("end-2c") != "\n": self.text.insert("end-1c", "\n") self.text.mark_set("iomark", "end-1c") self.set_line_and_column() def write(self, s, tags=()): try: self.text.mark_gravity("iomark", "right") OutputWindow.write(self, s, tags, "iomark") self.text.mark_gravity("iomark", "left") except: raise ###pass # ### 11Aug07 KBK if we are expecting exceptions # let's find out what they are and be specific. if self.canceled: self.canceled = 0 if not use_subprocess: raise KeyboardInterrupt
from os.path import basename as _basename if (not _sys.argv or _basename(_sys.argv[0]) != _basename(_filename)): _sys.argv = [_filename] import os as _os _os.chdir(%r) del _filename, _sys, _basename, _os \n""" % (filename, dirname)) interp.prepend_syspath(filename) # XXX KBK 03Jul04 When run w/o subprocess, runtime warnings still # go to __stderr__. With subprocess, they go to the shell. # Need to change streams in PyShell.ModifiedInterpreter. interp.runcode(code) return 'break' if macosxSupport.runningAsOSXApp(): # Tk-Cocoa in MacOSX is broken until at least # Tk 8.5.9, and without this rather # crude workaround IDLE would hang when a user # tries to run a module using the keyboard shortcut # (the menu item works fine). _run_module_event = run_module_event def run_module_event(self, event): self.editwin.text_frame.after(200, lambda: self.editwin.text_frame.event_generate('<<run-module-event-2>>')) return 'break' def getfilename(self): """Get source filename. If not saved, offer to save (or create) file
flist = idlelib.PyShell.PyShellFileList(root) macosxSupport.setupApp(root, flist) if enable_edit: if not (cmd or script): for filename in args: flist.open(filename) if not args: window_handle=flist.new() unique_id=str(uuid.uuid1()) if enable_shell: shell = flist.open_shell() if not shell: return # couldn't open shell if macosxSupport.runningAsOSXApp() and flist.dict: # On OSX: when the user has double-clicked on a file that causes # IDLE to be launched the shell window will open just in front of # the file she wants to see. Lower the interpreter window when # there are open files. shell.top.lower() shell = flist.pyshell # handle remaining options: if debug: shell.open_debugger() if startup: filename = os.environ.get("IDLESTARTUP") or \ os.environ.get("PYTHONSTARTUP") if filename and os.path.isfile(filename): shell.interp.execfile(filename)
def main(): global root global flist global use_subprocess use_subprocess = True enable_shell = True enable_edit = False debug = False cmd = None script = None startup = False try: opts, args = getopt.getopt(sys.argv[1:], 'c:deihnr:st:') except getopt.error as msg: sys.stderr.write('Error: %s\n' % str(msg)) sys.stderr.write(usage_msg) sys.exit(2) for o, a in opts: if o == '-c': cmd = a enable_shell = True if o == '-d': debug = True enable_shell = True if o == '-e': enable_edit = True enable_shell = False if o == '-h': sys.stdout.write(usage_msg) sys.exit() if o == '-i': enable_shell = True if o == '-n': use_subprocess = False if o == '-r': script = a if os.path.isfile(script): pass else: print 'No script file: ', script sys.exit() enable_shell = True if o == '-s': startup = True enable_shell = True if o == '-t': PyShell.shell_title = a enable_shell = True if args and args[0] == '-': cmd = sys.stdin.read() enable_shell = True for i in range(len(sys.path)): sys.path[i] = os.path.abspath(sys.path[i]) if args and args[0] == '-': sys.argv = [ ''] + args[1:] elif cmd: sys.argv = [ '-c'] + args elif script: sys.argv = [ script] + args elif args: enable_edit = True pathx = [] for filename in args: pathx.append(os.path.dirname(filename)) for dir in pathx: dir = os.path.abspath(dir) if dir not in sys.path: sys.path.insert(0, dir) else: dir = os.getcwd() if dir not in sys.path: sys.path.insert(0, dir) edit_start = idleConf.GetOption('main', 'General', 'editor-on-startup', type='bool') enable_edit = enable_edit or edit_start root = Tk(className='Idle') fixwordbreaks(root) root.withdraw() flist = PyShellFileList(root) macosxSupport.setupApp(root, flist) if enable_edit: if not (cmd or script): for filename in args: flist.open(filename) if not args: flist.new() if enable_shell: shell = flist.open_shell() if not shell: return if macosxSupport.runningAsOSXApp() and flist.dict: shell.top.lower() shell = flist.pyshell if debug: shell.open_debugger() if startup: filename = os.environ.get('IDLESTARTUP') or os.environ.get('PYTHONSTARTUP') if filename and os.path.isfile(filename): shell.interp.execfile(filename) if shell and cmd or script: shell.interp.runcommand('if 1:\n import sys as _sys\n _sys.argv = %r\n del _sys\n \n' % (sys.argv,)) if cmd: shell.interp.execsource(cmd) elif script: shell.interp.prepend_syspath(script) shell.interp.execfile(script) tkversionwarning = macosxSupport.tkVersionWarning(root) if tkversionwarning: shell.interp.runcommand(''.join(("print('", tkversionwarning, "')"))) root.mainloop() root.destroy() return
def main(): global flist, root, use_subprocess use_subprocess = True enable_shell = False enable_edit = False debug = False cmd = None script = None startup = False try: opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:") except getopt.error as msg: sys.stderr.write("Error: %s\n" % str(msg)) sys.stderr.write(usage_msg) sys.exit(2) for o, a in opts: if o == '-c': cmd = a enable_shell = True if o == '-d': debug = True enable_shell = True if o == '-e': enable_edit = True if o == '-h': sys.stdout.write(usage_msg) sys.exit() if o == '-i': enable_shell = True if o == '-n': use_subprocess = False if o == '-r': script = a if os.path.isfile(script): pass else: print("No script file: ", script) sys.exit() enable_shell = True if o == '-s': startup = True enable_shell = True if o == '-t': PyShell.shell_title = a enable_shell = True if args and args[0] == '-': cmd = sys.stdin.read() enable_shell = True # process sys.argv and sys.path: for i in range(len(sys.path)): sys.path[i] = os.path.abspath(sys.path[i]) if args and args[0] == '-': sys.argv = [''] + args[1:] elif cmd: sys.argv = ['-c'] + args elif script: sys.argv = [script] + args elif args: enable_edit = True pathx = [] for filename in args: pathx.append(os.path.dirname(filename)) for dir in pathx: dir = os.path.abspath(dir) if not dir in sys.path: sys.path.insert(0, dir) else: dir = os.getcwd() if dir not in sys.path: sys.path.insert(0, dir) # check the IDLE settings configuration (but command line overrides) edit_start = idleConf.GetOption('main', 'General', 'editor-on-startup', type='bool') enable_edit = enable_edit or edit_start enable_shell = enable_shell or not edit_start # start editor and/or shell windows: root = Tk(className="Idle") fixwordbreaks(root) root.withdraw() flist = PyShellFileList(root) macosxSupport.setupApp(root, flist) if enable_edit: if not (cmd or script): for filename in args: flist.open(filename) if not args: flist.new() if enable_shell: shell = flist.open_shell() if not shell: return # couldn't open shell if macosxSupport.runningAsOSXApp() and flist.dict: # On OSX: when the user has double-clicked on a file that causes # IDLE to be launched the shell window will open just in front of # the file she wants to see. Lower the interpreter window when # there are open files. shell.top.lower() shell = flist.pyshell # handle remaining options: if debug: shell.open_debugger() if startup: filename = os.environ.get("IDLESTARTUP") or \ os.environ.get("PYTHONSTARTUP") if filename and os.path.isfile(filename): shell.interp.execfile(filename) if shell and cmd or script: shell.interp.runcommand("""if 1: import sys as _sys _sys.argv = %r del _sys \n""" % (sys.argv,)) if cmd: shell.interp.execsource(cmd) elif script: shell.interp.prepend_syspath(script) shell.interp.execfile(script) root.mainloop() root.destroy()
class ScriptBinding: menudefs = [('run', [ None, ('Check Module', '<<check-module>>'), ('Run Module', '<<run-module>>') ])] def __init__(self, editwin): self.editwin = editwin self.flist = self.editwin.flist self.root = self.editwin.root if macosxSupport.runningAsOSXApp(): self.editwin.text_frame.bind('<<run-module-event-2>>', self._run_module_event) def check_module_event(self, event): filename = self.getfilename() if not filename: return 'break' if not self.checksyntax(filename): return 'break' if not self.tabnanny(filename): return 'break' def tabnanny(self, filename): f = open(filename, 'r') try: tabnanny.process_tokens(tokenize.generate_tokens(f.readline)) except tokenize.TokenError as msg: msgtxt, (lineno, start) = msg self.editwin.gotoline(lineno) self.errorbox('Tabnanny Tokenizing Error', 'Token Error: %s' % msgtxt) return False except tabnanny.NannyNag as nag: self.editwin.gotoline(nag.get_lineno()) self.errorbox('Tab/space error', indent_message) return False return True def checksyntax(self, filename): self.shell = shell = self.flist.open_shell() saved_stream = shell.get_warning_stream() shell.set_warning_stream(shell.stderr) f = open(filename, 'r') source = f.read() f.close() if '\r' in source: source = re.sub('\\r\\n', '\n', source) source = re.sub('\\r', '\n', source) if source and source[-1] != '\n': source = source + '\n' text = self.editwin.text text.tag_remove('ERROR', '1.0', 'end') try: try: return compile(source, filename, 'exec') except (SyntaxError, OverflowError) as err: try: msg, (errorfilename, lineno, offset, line) = err if not errorfilename: err.args = (msg, (filename, lineno, offset, line)) err.filename = filename self.colorize_syntax_error(msg, lineno, offset) except: msg = '*** ' + str(err) self.errorbox('Syntax error', "There's an error in your program:\n" + msg) return False finally: shell.set_warning_stream(saved_stream) def colorize_syntax_error(self, msg, lineno, offset): text = self.editwin.text pos = '0.0 + %d lines + %d chars' % (lineno - 1, offset - 1) text.tag_add('ERROR', pos) char = text.get(pos) if char and char in IDENTCHARS: text.tag_add('ERROR', pos + ' wordstart', pos) if '\n' == text.get(pos): text.mark_set('insert', pos) else: text.mark_set('insert', pos + '+1c') text.see(pos) def run_module_event(self, event): """Run the module after setting up the environment. First check the syntax. If OK, make sure the shell is active and then transfer the arguments, set the run environment's working directory to the directory of the module being executed and also add that directory to its sys.path if not already included. """ filename = self.getfilename() if not filename: return 'break' code = self.checksyntax(filename) if not code: return 'break' if not self.tabnanny(filename): return 'break' shell = self.shell interp = shell.interp if PyShell.use_subprocess: shell.restart_shell() dirname = os.path.dirname(filename) interp.runcommand( 'if 1:\n _filename = %r\n import sys as _sys\n from os.path import basename as _basename\n if (not _sys.argv or\n _basename(_sys.argv[0]) != _basename(_filename)):\n _sys.argv = [_filename]\n import os as _os\n _os.chdir(%r)\n del _filename, _sys, _basename, _os\n \n' % (filename, dirname)) interp.prepend_syspath(filename) interp.runcode(code) return 'break' if macosxSupport.runningAsOSXApp(): _run_module_event = run_module_event def run_module_event(self, event): self.editwin.text_frame.after( 200, lambda: self.editwin.text_frame.event_generate( '<<run-module-event-2>>')) return 'break' def getfilename(self): """Get source filename. If not saved, offer to save (or create) file The debugger requires a source file. Make sure there is one, and that the current version of the source buffer has been saved. If the user declines to save or cancels the Save As dialog, return None. If the user has configured IDLE for Autosave, the file will be silently saved if it already exists and is dirty. """ filename = self.editwin.io.filename if not self.editwin.get_saved(): autosave = idleConf.GetOption('main', 'General', 'autosave', type='bool') if autosave and filename: self.editwin.io.save(None) else: confirm = self.ask_save_dialog() self.editwin.text.focus_set() if confirm: self.editwin.io.save(None) filename = self.editwin.io.filename else: filename = None return filename def ask_save_dialog(self): msg = 'Source Must Be Saved\n' + ' ' + 'OK to Save?' confirm = tkMessageBox.askokcancel(title='Save Before Run or Check', message=msg, default=tkMessageBox.OK, master=self.editwin.text) return confirm def errorbox(self, title, message): tkMessageBox.showerror(title, message, master=self.editwin.text) self.editwin.text.focus_set()
def _make_toolbar(self): if self.TB is not None: return # toolbar exists top = self.editwin.top f = Frame(top) widgets = self.editwin.top.pack_slaves() widgets = list(widgets) # list for Python 3 support f.pack(side="top", fill=X, before=widgets[0]) # make toolbar play nicely with CodeContext f.config(height=8) mvar = [StringVar(top), StringVar(top)] Separator = Label try: osx = macosxSupport.runningAsOSXApp() or sys.platform == "darwin" except: osx = False toolbar = [ ( Button(f, command=lambda: self.toolbar("titles"), text=">", width=1 if not osx else 2), None, "Show SubCode Labels", ), ( Button(f, command=lambda: self.toolbar("ins"), text="##", width=2 if not osx else 3), None, "Insert SubCode Marker", ), (Separator(f), {"fill": Y, "pady": 0, "padx": 4}, None), ( Button(f, command=lambda: self.toolbar("minus"), text="-", width=1 if not osx else 2), None, "Subtract from number by cursor then run subcode", ), (Entry(f, width=6, justify="center", textvar=mvar[0]), {"fill": Y}, "+ - value"), ( Button(f, command=lambda: self.toolbar("plus"), text="+", width=1 if not osx else 2), None, "Add to number by cursor then run subcode", ), (Separator(f), {"fill": Y, "pady": 0, "padx": 4}, None), ( Button(f, command=lambda: self.toolbar("div"), text="/", width=1 if not osx else 2), None, "Divide number by cursor then run subcode", ), (Entry(f, width=6, justify="center", textvar=mvar[1]), {"fill": Y}, "* / value"), ( Button(f, command=lambda: self.toolbar("mult"), text="*", width=1 if not osx else 2), None, "Multiply number by cursor then run subcode", ), (Separator(f), {"fill": Y, "pady": 0, "padx": 4}, None), ( Button(f, command=lambda: self.toolbar("run_subcode"), text="RS", width=2 if not osx else 4), None, "Run SubCode", ), ( Button(f, command=lambda: self.toolbar("run_subcode_proceed"), text="RSP", width=3 if not osx else 4), None, "Run SubCode and Proceed", ), ( Button(f, command=lambda: self.toolbar("run_all"), text="RA", width=2 if not osx else 4), None, "Run All SubCodes", ), (Separator(f), {"fill": Y, "pady": 0, "padx": 4}, None), ] mvar[0].set("1.0") mvar[1].set("1.1") self.mvar = mvar for i, cfg, tooltip in toolbar: if cfg is None: cfg = {} try: i.configure(pady=0, padx=7) i.configure(wraplength=0) i.configure(borderwidth=1) except: # catch ALL THE ERRORS # print 'error',i, cfg, tooltip pass i.pack(side="left", **cfg) if tooltip is not None: ToolTip.ToolTip(i, " %s " % tooltip) self.TB = f self.TITLES = toolbar[0][0] # pointer to the titles button
def _make_toolbar(self): if self.TB is not None: return # toolbar exists top = self.editwin.top f = Frame(top) widgets = self.editwin.top.pack_slaves() widgets = list(widgets) # list for Python 3 support f.pack(side='top', fill=X, before=widgets[0]) # make toolbar play nicely with CodeContext f.config(height=8) mvar = [StringVar(top), StringVar(top)] Separator = Label try: osx = (macosxSupport.runningAsOSXApp() or sys.platform == 'darwin') except: osx = False toolbar = [(Button(f, command=lambda: self.toolbar('titles'), text='>', width=1 if not osx else 2), None, 'Show %s Labels' % SUBCODE_STR), (Button(f, command=lambda: self.toolbar('ins'), text='##', width=2 if not osx else 3), None, 'Insert %s Marker' % SUBCODE_STR), (Separator(f), {'fill':Y, 'pady':0, 'padx':4}, None), (Button(f, command=lambda: self.toolbar('minus'), text='-', width=1 if not osx else 2), None, 'Subtract from number by cursor then run %s' % SUBCODE_STR.lower()), (Entry(f, width=6, justify='center', textvar=mvar[0]), {'fill':Y}, '+ - value'), (Button(f, command=lambda: self.toolbar('plus'), text='+', width=1 if not osx else 2), None, 'Add to number by cursor then run %s' % SUBCODE_STR.lower()), (Separator(f), {'fill':Y, 'pady':0, 'padx':4}, None), (Button(f, command=lambda: self.toolbar('div'), text='/', width=1 if not osx else 2), None, 'Divide number by cursor then run %s' % SUBCODE_STR.lower()), (Entry(f, width=6, justify='center', textvar=mvar[1]), {'fill':Y}, '* / value'), (Button(f, command=lambda: self.toolbar('mult'), text='*', width=1 if not osx else 2), None, 'Multiply number by cursor then run %s' % SUBCODE_STR.lower()), (Separator(f), {'fill':Y, 'pady':0, 'padx':4}, None), (Button(f, command=lambda: self.toolbar('run_subcode'), text='R%s' % SUBCODE_STR[0].upper(), width=2 if not osx else 4), None, 'Run %s' % SUBCODE_STR), (Button(f, command=lambda: self.toolbar('run_subcode_proceed'), text='R%sP' % SUBCODE_STR[0].upper(), width=3 if not osx else 4), None, 'Run %s and Proceed' % SUBCODE_STR), (Button(f, command=lambda: self.toolbar('run_all'), text='RA', width=2 if not osx else 4), None, 'Run All %ss' % SUBCODE_STR), (Separator(f), {'fill':Y, 'pady':0, 'padx':4}, None), ] mvar[0].set('1.0') mvar[1].set('1.1') self.mvar = mvar for i, cfg, tooltip in toolbar: if cfg is None: cfg = {} try: i.configure(pady=0, padx=7) i.configure(wraplength=0) i.configure(borderwidth=1) except: # catch ALL THE ERRORS #print 'error',i, cfg, tooltip pass i.pack(side='left', **cfg) if tooltip is not None: ToolTip.ToolTip(i, ' %s ' % tooltip) self.TB = f self.TITLES = toolbar[0][0] # pointer to the titles button
class EditorWindow(object): from idlelib.Percolator import Percolator from idlelib.ColorDelegator import ColorDelegator from idlelib.UndoDelegator import UndoDelegator from idlelib.IOBinding import IOBinding, filesystemencoding, encoding from idlelib import Bindings from Tkinter import Toplevel from idlelib.MultiStatusBar import MultiStatusBar help_url = None def __init__(self, flist=None, filename=None, key=None, root=None): if EditorWindow.help_url is None: dochome = os.path.join(sys.prefix, 'Doc', 'index.html') if sys.platform.count('linux'): pyver = 'python-docs-' + '%s.%s.%s' % sys.version_info[:3] if os.path.isdir('/var/www/html/python/'): dochome = '/var/www/html/python/index.html' else: basepath = '/usr/share/doc/' dochome = os.path.join(basepath, pyver, 'Doc', 'index.html') elif sys.platform[:3] == 'win': chmfile = os.path.join(sys.prefix, 'Doc', 'Python%s.chm' % _sphinx_version()) if os.path.isfile(chmfile): dochome = chmfile elif macosxSupport.runningAsOSXApp(): dochome = os.path.join(sys.prefix, 'Resources/English.lproj/Documentation/index.html') dochome = os.path.normpath(dochome) if os.path.isfile(dochome): EditorWindow.help_url = dochome if sys.platform == 'darwin': EditorWindow.help_url = 'file://' + EditorWindow.help_url else: EditorWindow.help_url = 'http://docs.python.org/%d.%d' % sys.version_info[:2] currentTheme = idleConf.CurrentTheme() self.flist = flist root = root or flist.root self.root = root try: sys.ps1 except AttributeError: sys.ps1 = '>>> ' self.menubar = Menu(root) self.top = top = WindowList.ListedToplevel(root, menu=self.menubar) if flist: self.tkinter_vars = flist.vars self.top.instance_dict = flist.inversedict else: self.tkinter_vars = {} self.top.instance_dict = {} self.recent_files_path = os.path.join(idleConf.GetUserCfgDir(), 'recent-files.lst') self.text_frame = text_frame = Frame(top) self.vbar = vbar = Scrollbar(text_frame, name='vbar') self.width = idleConf.GetOption('main', 'EditorWindow', 'width') text_options = {'name': 'text', 'padx': 5, 'wrap': 'none', 'width': self.width, 'height': idleConf.GetOption('main', 'EditorWindow', 'height') } if TkVersion >= 8.5: text_options['tabstyle'] = 'wordprocessor' self.text = text = MultiCallCreator(Text)(text_frame, **text_options) self.top.focused_widget = self.text self.createmenubar() self.apply_bindings() self.top.protocol('WM_DELETE_WINDOW', self.close) self.top.bind('<<close-window>>', self.close_event) if macosxSupport.runningAsOSXApp(): text.bind('<<close-window>>', self.close_event) text.bind('<Control-Button-1>', self.right_menu_event) else: text.bind('<3>', self.right_menu_event) text.bind('<<cut>>', self.cut) text.bind('<<copy>>', self.copy) text.bind('<<paste>>', self.paste) text.bind('<<center-insert>>', self.center_insert_event) text.bind('<<help>>', self.help_dialog) text.bind('<<python-docs>>', self.python_docs) text.bind('<<about-idle>>', self.about_dialog) text.bind('<<open-config-dialog>>', self.config_dialog) text.bind('<<open-module>>', self.open_module) text.bind('<<do-nothing>>', lambda event: 'break') text.bind('<<select-all>>', self.select_all) text.bind('<<remove-selection>>', self.remove_selection) text.bind('<<find>>', self.find_event) text.bind('<<find-again>>', self.find_again_event) text.bind('<<find-in-files>>', self.find_in_files_event) text.bind('<<find-selection>>', self.find_selection_event) text.bind('<<replace>>', self.replace_event) text.bind('<<goto-line>>', self.goto_line_event) text.bind('<<smart-backspace>>', self.smart_backspace_event) text.bind('<<newline-and-indent>>', self.newline_and_indent_event) text.bind('<<smart-indent>>', self.smart_indent_event) text.bind('<<indent-region>>', self.indent_region_event) text.bind('<<dedent-region>>', self.dedent_region_event) text.bind('<<comment-region>>', self.comment_region_event) text.bind('<<uncomment-region>>', self.uncomment_region_event) text.bind('<<tabify-region>>', self.tabify_region_event) text.bind('<<untabify-region>>', self.untabify_region_event) text.bind('<<toggle-tabs>>', self.toggle_tabs_event) text.bind('<<change-indentwidth>>', self.change_indentwidth_event) text.bind('<Left>', self.move_at_edge_if_selection(0)) text.bind('<Right>', self.move_at_edge_if_selection(1)) text.bind('<<del-word-left>>', self.del_word_left) text.bind('<<del-word-right>>', self.del_word_right) text.bind('<<beginning-of-line>>', self.home_callback) if flist: flist.inversedict[self] = key if key: flist.dict[key] = self text.bind('<<open-new-window>>', self.new_callback) text.bind('<<close-all-windows>>', self.flist.close_all_callback) text.bind('<<open-class-browser>>', self.open_class_browser) text.bind('<<open-path-browser>>', self.open_path_browser) self.set_status_bar() vbar['command'] = text.yview vbar.pack(side=RIGHT, fill=Y) text['yscrollcommand'] = vbar.set fontWeight = 'normal' if idleConf.GetOption('main', 'EditorWindow', 'font-bold', type='bool'): fontWeight = 'bold' text.config(font=(idleConf.GetOption('main', 'EditorWindow', 'font'), idleConf.GetOption('main', 'EditorWindow', 'font-size'), fontWeight)) text_frame.pack(side=LEFT, fill=BOTH, expand=1) text.pack(side=TOP, fill=BOTH, expand=1) text.focus_set() usespaces = idleConf.GetOption('main', 'Indent', 'use-spaces', type='bool') self.usetabs = not usespaces self.tabwidth = 8 self.indentwidth = self.tabwidth self.set_notabs_indentwidth() self.context_use_ps1 = False self.num_context_lines = (50, 500, 5000000) self.per = per = self.Percolator(text) self.undo = undo = self.UndoDelegator() per.insertfilter(undo) text.undo_block_start = undo.undo_block_start text.undo_block_stop = undo.undo_block_stop undo.set_saved_change_hook(self.saved_change_hook) self.io = io = self.IOBinding(self) io.set_filename_change_hook(self.filename_change_hook) self.recent_files_menu = Menu(self.menubar) self.menudict['file'].insert_cascade(3, label='Recent Files', underline=0, menu=self.recent_files_menu) self.update_recent_files_list() self.color = None if filename: if os.path.exists(filename) and not os.path.isdir(filename): io.loadfile(filename) else: io.set_filename(filename) self.ResetColorizer() self.saved_change_hook() self.set_indentation_params(self.ispythonsource(filename)) self.load_extensions() menu = self.menudict.get('windows') if menu: end = menu.index('end') if end is None: end = -1 if end >= 0: menu.add_separator() end = end + 1 self.wmenu_end = end WindowList.register_callback(self.postwindowsmenu) self.askyesno = tkMessageBox.askyesno self.askinteger = tkSimpleDialog.askinteger self.showerror = tkMessageBox.showerror return def _filename_to_unicode(self, filename): """convert filename to unicode in order to display it in Tk""" if isinstance(filename, unicode) or not filename: return filename try: return filename.decode(self.filesystemencoding) except UnicodeDecodeError: try: return filename.decode(self.encoding) except UnicodeDecodeError: return filename.decode('iso8859-1') def new_callback(self, event): dirname, basename = self.io.defaultfilename() self.flist.new(dirname) return 'break' def home_callback(self, event): if event.state & 4 != 0 and event.keysym == 'Home': return if self.text.index('iomark') and self.text.compare('iomark', '<=', 'insert lineend') and self.text.compare('insert linestart', '<=', 'iomark'): insertpt = int(self.text.index('iomark').split('.')[1]) else: line = self.text.get('insert linestart', 'insert lineend') for insertpt in xrange(len(line)): if line[insertpt] not in (' ', '\t'): break else: insertpt = len(line) lineat = int(self.text.index('insert').split('.')[1]) if insertpt == lineat: insertpt = 0 dest = 'insert linestart+' + str(insertpt) + 'c' if event.state & 1 == 0: self.text.tag_remove('sel', '1.0', 'end') else: if not self.text.index('sel.first'): self.text.mark_set('my_anchor', 'insert') elif self.text.compare(self.text.index('sel.first'), '<', self.text.index('insert')): self.text.mark_set('my_anchor', 'sel.first') else: self.text.mark_set('my_anchor', 'sel.last') first = self.text.index(dest) last = self.text.index('my_anchor') if self.text.compare(first, '>', last): first, last = last, first self.text.tag_remove('sel', '1.0', 'end') self.text.tag_add('sel', first, last) self.text.mark_set('insert', dest) self.text.see('insert') return 'break' def set_status_bar(self): self.status_bar = self.MultiStatusBar(self.top) if macosxSupport.runningAsOSXApp(): self.status_bar.set_label('_padding1', ' ', side=RIGHT) self.status_bar.set_label('column', 'Col: ?', side=RIGHT) self.status_bar.set_label('line', 'Ln: ?', side=RIGHT) self.status_bar.pack(side=BOTTOM, fill=X) self.text.bind('<<set-line-and-column>>', self.set_line_and_column) self.text.event_add('<<set-line-and-column>>', '<KeyRelease>', '<ButtonRelease>') self.text.after_idle(self.set_line_and_column) def set_line_and_column(self, event=None): line, column = self.text.index(INSERT).split('.') self.status_bar.set_label('column', 'Col: %s' % column) self.status_bar.set_label('line', 'Ln: %s' % line) menu_specs = [ ('file', '_File'), ('edit', '_Edit'), ('format', 'F_ormat'), ('run', '_Run'), ('options', '_Options'), ('windows', '_Windows'), ('help', '_Help')] if macosxSupport.runningAsOSXApp(): del menu_specs[-3] menu_specs[-2] = ('windows', '_Window') def createmenubar(self): mbar = self.menubar self.menudict = menudict = {} for name, label in self.menu_specs: underline, label = prepstr(label) menudict[name] = menu = Menu(mbar, name=name) mbar.add_cascade(label=label, menu=menu, underline=underline) if macosxSupport.isCarbonAquaTk(self.root): menudict['application'] = menu = Menu(mbar, name='apple') mbar.add_cascade(label='IDLE', menu=menu) self.fill_menus() self.base_helpmenu_length = self.menudict['help'].index(END) self.reset_help_menu_entries() def postwindowsmenu(self): menu = self.menudict['windows'] end = menu.index('end') if end is None: end = -1 if end > self.wmenu_end: menu.delete(self.wmenu_end + 1, end) WindowList.add_windows_to_menu(menu) return rmenu = None def right_menu_event(self, event): self.text.tag_remove('sel', '1.0', 'end') self.text.mark_set('insert', '@%d,%d' % (event.x, event.y)) if not self.rmenu: self.make_rmenu() rmenu = self.rmenu self.event = event iswin = sys.platform[:3] == 'win' if iswin: self.text.config(cursor='arrow') rmenu.tk_popup(event.x_root, event.y_root) if iswin: self.text.config(cursor='ibeam') rmenu_specs = [ ('Close', '<<close-window>>')] def make_rmenu(self): rmenu = Menu(self.text, tearoff=0) for label, eventname in self.rmenu_specs: def command(text=self.text, eventname=eventname): text.event_generate(eventname) rmenu.add_command(label=label, command=command) self.rmenu = rmenu def about_dialog(self, event=None): aboutDialog.AboutDialog(self.top, 'About IDLE') def config_dialog(self, event=None): configDialog.ConfigDialog(self.top, 'Settings') def help_dialog(self, event=None): fn = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'help.txt') textView.view_file(self.top, 'Help', fn) def python_docs(self, event=None): if sys.platform[:3] == 'win': try: os.startfile(self.help_url) except WindowsError as why: tkMessageBox.showerror(title='Document Start Failure', message=str(why), parent=self.text) else: webbrowser.open(self.help_url) return 'break' def cut(self, event): self.text.event_generate('<<Cut>>') return 'break' def copy(self, event): if not self.text.tag_ranges('sel'): return self.text.event_generate('<<Copy>>') return 'break' def paste(self, event): self.text.event_generate('<<Paste>>') self.text.see('insert') return 'break' def select_all(self, event=None): self.text.tag_add('sel', '1.0', 'end-1c') self.text.mark_set('insert', '1.0') self.text.see('insert') return 'break' def remove_selection(self, event=None): self.text.tag_remove('sel', '1.0', 'end') self.text.see('insert') def move_at_edge_if_selection(self, edge_index): """Cursor move begins at start or end of selection When a left/right cursor key is pressed create and return to Tkinter a function which causes a cursor move from the associated edge of the selection. """ self_text_index = self.text.index self_text_mark_set = self.text.mark_set edges_table = ('sel.first+1c', 'sel.last-1c') def move_at_edge(event): if event.state & 5 == 0: try: self_text_index('sel.first') self_text_mark_set('insert', edges_table[edge_index]) except TclError: pass return move_at_edge def del_word_left(self, event): self.text.event_generate('<Meta-Delete>') return 'break' def del_word_right(self, event): self.text.event_generate('<Meta-d>') return 'break' def find_event(self, event): SearchDialog.find(self.text) return 'break' def find_again_event(self, event): SearchDialog.find_again(self.text) return 'break' def find_selection_event(self, event): SearchDialog.find_selection(self.text) return 'break' def find_in_files_event(self, event): GrepDialog.grep(self.text, self.io, self.flist) return 'break' def replace_event(self, event): ReplaceDialog.replace(self.text) return 'break' def goto_line_event(self, event): text = self.text lineno = tkSimpleDialog.askinteger('Goto', 'Go to line number:', parent=text) if lineno is None: return 'break' else: if lineno <= 0: text.bell() return 'break' text.mark_set('insert', '%d.0' % lineno) text.see('insert') return def open_module(self, event=None): try: name = self.text.get('sel.first', 'sel.last') except TclError: name = '' else: name = name.strip() name = tkSimpleDialog.askstring('Module', 'Enter the name of a Python module\nto search on sys.path and open:', parent=self.text, initialvalue=name) if name: name = name.strip() if not name: return try: f, file, (suffix, mode, type) = _find_module(name) except (NameError, ImportError) as msg: tkMessageBox.showerror('Import error', str(msg), parent=self.text) return if type != imp.PY_SOURCE: tkMessageBox.showerror('Unsupported type', '%s is not a source module' % name, parent=self.text) return if f: f.close() if self.flist: self.flist.open(file) else: self.io.loadfile(file) def open_class_browser(self, event=None): filename = self.io.filename if not filename: tkMessageBox.showerror('No filename', 'This buffer has no associated filename', master=self.text) self.text.focus_set() return None else: head, tail = os.path.split(filename) base, ext = os.path.splitext(tail) from idlelib import ClassBrowser ClassBrowser.ClassBrowser(self.flist, base, [head]) return None def open_path_browser(self, event=None): from idlelib import PathBrowser PathBrowser.PathBrowser(self.flist) def gotoline(self, lineno): if lineno is not None and lineno > 0: self.text.mark_set('insert', '%d.0' % lineno) self.text.tag_remove('sel', '1.0', 'end') self.text.tag_add('sel', 'insert', 'insert +1l') self.center() return def ispythonsource(self, filename): if not filename or os.path.isdir(filename): return True base, ext = os.path.splitext(os.path.basename(filename)) if os.path.normcase(ext) in ('.py', '.pyw'): return True try: f = open(filename) line = f.readline() f.close() except IOError: return False return line.startswith('#!') and line.find('python') >= 0 def close_hook(self): if self.flist: self.flist.unregister_maybe_terminate(self) self.flist = None return def set_close_hook(self, close_hook): self.close_hook = close_hook def filename_change_hook(self): if self.flist: self.flist.filename_changed_edit(self) self.saved_change_hook() self.top.update_windowlist_registry(self) self.ResetColorizer() def _addcolorizer(self): if self.color: return if self.ispythonsource(self.io.filename): self.color = self.ColorDelegator() if self.color: self.per.removefilter(self.undo) self.per.insertfilter(self.color) self.per.insertfilter(self.undo) def _rmcolorizer(self): if not self.color: return else: self.color.removecolors() self.per.removefilter(self.color) self.color = None return def ResetColorizer(self): """Update the colour theme""" self._rmcolorizer() self._addcolorizer() theme = idleConf.GetOption('main', 'Theme', 'name') normal_colors = idleConf.GetHighlight(theme, 'normal') cursor_color = idleConf.GetHighlight(theme, 'cursor', fgBg='fg') select_colors = idleConf.GetHighlight(theme, 'hilite') self.text.config(foreground=normal_colors['foreground'], background=normal_colors['background'], insertbackground=cursor_color, selectforeground=select_colors['foreground'], selectbackground=select_colors['background']) def ResetFont(self): """Update the text widgets' font if it is changed""" fontWeight = 'normal' if idleConf.GetOption('main', 'EditorWindow', 'font-bold', type='bool'): fontWeight = 'bold' self.text.config(font=(idleConf.GetOption('main', 'EditorWindow', 'font'), idleConf.GetOption('main', 'EditorWindow', 'font-size'), fontWeight)) def RemoveKeybindings(self): """Remove the keybindings before they are changed.""" self.Bindings.default_keydefs = keydefs = idleConf.GetCurrentKeySet() for event, keylist in keydefs.items(): self.text.event_delete(event, *keylist) for extensionName in self.get_standard_extension_names(): xkeydefs = idleConf.GetExtensionBindings(extensionName) if xkeydefs: for event, keylist in xkeydefs.items(): self.text.event_delete(event, *keylist) def ApplyKeybindings(self): """Update the keybindings after they are changed""" self.Bindings.default_keydefs = keydefs = idleConf.GetCurrentKeySet() self.apply_bindings() for extensionName in self.get_standard_extension_names(): xkeydefs = idleConf.GetExtensionBindings(extensionName) if xkeydefs: self.apply_bindings(xkeydefs) menuEventDict = {} for menu in self.Bindings.menudefs: menuEventDict[menu[0]] = {} for item in menu[1]: if item: menuEventDict[menu[0]][prepstr(item[0])[1]] = item[1] for menubarItem in self.menudict.keys(): menu = self.menudict[menubarItem] end = menu.index(END) + 1 for index in range(0, end): if menu.type(index) == 'command': accel = menu.entrycget(index, 'accelerator') if accel: itemName = menu.entrycget(index, 'label') event = '' if menubarItem in menuEventDict: if itemName in menuEventDict[menubarItem]: event = menuEventDict[menubarItem][itemName] if event: accel = get_accelerator(keydefs, event) menu.entryconfig(index, accelerator=accel) def set_notabs_indentwidth(self): """Update the indentwidth if changed and not using tabs in this window""" if not self.usetabs: self.indentwidth = idleConf.GetOption('main', 'Indent', 'num-spaces', type='int') def reset_help_menu_entries(self): """Update the additional help entries on the Help menu""" help_list = idleConf.GetAllExtraHelpSourcesList() helpmenu = self.menudict['help'] helpmenu_length = helpmenu.index(END) if helpmenu_length > self.base_helpmenu_length: helpmenu.delete(self.base_helpmenu_length + 1, helpmenu_length) if help_list: helpmenu.add_separator() for entry in help_list: cmd = self.__extra_help_callback(entry[1]) helpmenu.add_command(label=entry[0], command=cmd) self.menudict['help'] = helpmenu def __extra_help_callback(self, helpfile): """Create a callback with the helpfile value frozen at definition time""" def display_extra_help(helpfile=helpfile): if not helpfile.startswith(('www', 'http')): helpfile = os.path.normpath(helpfile) if sys.platform[:3] == 'win': try: os.startfile(helpfile) except WindowsError as why: tkMessageBox.showerror(title='Document Start Failure', message=str(why), parent=self.text) else: webbrowser.open(helpfile) return display_extra_help def update_recent_files_list(self, new_file=None): """Load and update the recent files list and menus""" rf_list = [] if os.path.exists(self.recent_files_path): rf_list_file = open(self.recent_files_path, 'r') try: rf_list = rf_list_file.readlines() finally: rf_list_file.close() if new_file: new_file = os.path.abspath(new_file) + '\n' if new_file in rf_list: rf_list.remove(new_file) rf_list.insert(0, new_file) bad_paths = [] for path in rf_list: if '\x00' in path or not os.path.exists(path[0:-1]): bad_paths.append(path) rf_list = [ path for path in rf_list if path not in bad_paths ] ulchars = '1234567890ABCDEFGHIJK' rf_list = rf_list[0:len(ulchars)] rf_file = open(self.recent_files_path, 'w') try: rf_file.writelines(rf_list) finally: rf_file.close() for instance in self.top.instance_dict.keys(): menu = instance.recent_files_menu menu.delete(1, END) for i, file_name in enumerate(rf_list): file_name = file_name.rstrip() ufile_name = self._filename_to_unicode(file_name) callback = instance.__recent_file_callback(file_name) menu.add_command(label=ulchars[i] + ' ' + ufile_name, command=callback, underline=0) def __recent_file_callback(self, file_name): def open_recent_file(fn_closure=file_name): self.io.open(editFile=fn_closure) return open_recent_file def saved_change_hook(self): short = self.short_title() long = self.long_title() if short and long: title = short + ' - ' + long elif short: title = short elif long: title = long else: title = 'Untitled' icon = short or long or title if not self.get_saved(): title = '*%s*' % title icon = '*%s' % icon self.top.wm_title(title) self.top.wm_iconname(icon) def get_saved(self): return self.undo.get_saved() def set_saved(self, flag): self.undo.set_saved(flag) def reset_undo(self): self.undo.reset_undo() def short_title(self): filename = self.io.filename if filename: filename = os.path.basename(filename) return self._filename_to_unicode(filename) def long_title(self): return self._filename_to_unicode(self.io.filename or '') def center_insert_event(self, event): self.center() def center(self, mark='insert'): text = self.text top, bot = self.getwindowlines() lineno = self.getlineno(mark) height = bot - top newtop = max(1, lineno - height // 2) text.yview(float(newtop)) def getwindowlines(self): text = self.text top = self.getlineno('@0,0') bot = self.getlineno('@0,65535') if top == bot and text.winfo_height() == 1: height = int(text['height']) bot = top + height - 1 return (top, bot) def getlineno(self, mark='insert'): text = self.text return int(float(text.index(mark))) def get_geometry(self): """Return (width, height, x, y)""" geom = self.top.wm_geometry() m = re.match('(\\d+)x(\\d+)\\+(-?\\d+)\\+(-?\\d+)', geom) tuple = map(int, m.groups()) return tuple def close_event(self, event): self.close() def maybesave(self): if self.io: if not self.get_saved(): if self.top.state() != 'normal': self.top.deiconify() self.top.lower() self.top.lift() return self.io.maybesave() def close(self): reply = self.maybesave() if str(reply) != 'cancel': self._close() return reply def _close(self): if self.io.filename: self.update_recent_files_list(new_file=self.io.filename) WindowList.unregister_callback(self.postwindowsmenu) self.unload_extensions() self.io.close() self.io = None self.undo = None if self.color: self.color.close(False) self.color = None self.text = None self.tkinter_vars = None self.per.close() self.per = None self.top.destroy() if self.close_hook: self.close_hook() return def load_extensions(self): self.extensions = {} self.load_standard_extensions() def unload_extensions(self): for ins in self.extensions.values(): if hasattr(ins, 'close'): ins.close() self.extensions = {} def load_standard_extensions(self): for name in self.get_standard_extension_names(): try: self.load_extension(name) except: print 'Failed to load extension', repr(name) import traceback traceback.print_exc() def get_standard_extension_names(self): return idleConf.GetExtensions(editor_only=True) def load_extension(self, name): try: mod = __import__(name, globals(), locals(), []) except ImportError: print '\nFailed to import extension: ', name return cls = getattr(mod, name) keydefs = idleConf.GetExtensionBindings(name) if hasattr(cls, 'menudefs'): self.fill_menus(cls.menudefs, keydefs) ins = cls(self) self.extensions[name] = ins if keydefs: self.apply_bindings(keydefs) for vevent in keydefs.keys(): methodname = vevent.replace('-', '_') while methodname[:1] == '<': methodname = methodname[1:] while methodname[-1:] == '>': methodname = methodname[:-1] methodname = methodname + '_event' if hasattr(ins, methodname): self.text.bind(vevent, getattr(ins, methodname)) def apply_bindings(self, keydefs=None): if keydefs is None: keydefs = self.Bindings.default_keydefs text = self.text text.keydefs = keydefs for event, keylist in keydefs.items(): if keylist: text.event_add(event, *keylist) return def fill_menus(self, menudefs=None, keydefs=None): """Add appropriate entries to the menus and submenus Menus that are absent or None in self.menudict are ignored. """ if menudefs is None: menudefs = self.Bindings.menudefs if keydefs is None: keydefs = self.Bindings.default_keydefs menudict = self.menudict text = self.text for mname, entrylist in menudefs: menu = menudict.get(mname) if not menu: continue for entry in entrylist: if not entry: menu.add_separator() else: label, eventname = entry checkbutton = label[:1] == '!' if checkbutton: label = label[1:] underline, label = prepstr(label) accelerator = get_accelerator(keydefs, eventname) def command(text=text, eventname=eventname): text.event_generate(eventname) if checkbutton: var = self.get_var_obj(eventname, BooleanVar) menu.add_checkbutton(label=label, underline=underline, command=command, accelerator=accelerator, variable=var) else: menu.add_command(label=label, underline=underline, command=command, accelerator=accelerator) return def getvar(self, name): var = self.get_var_obj(name) if var: value = var.get() return value raise NameError, name def setvar(self, name, value, vartype=None): var = self.get_var_obj(name, vartype) if var: var.set(value) else: raise NameError, name def get_var_obj(self, name, vartype=None): var = self.tkinter_vars.get(name) if not var and vartype: self.tkinter_vars[name] = var = vartype(self.text) return var def is_char_in_string(self, text_index): if self.color: return self.text.tag_prevrange('TODO', text_index) or 'STRING' in self.text.tag_names(text_index) else: return 1 def get_selection_indices(self): try: first = self.text.index('sel.first') last = self.text.index('sel.last') return ( first, last) except TclError: return (None, None) return None def get_tabwidth(self): current = self.text['tabs'] or TK_TABWIDTH_DEFAULT return int(current) def set_tabwidth(self, newtabwidth): text = self.text if self.get_tabwidth() != newtabwidth: pixels = text.tk.call('font', 'measure', text['font'], '-displayof', text.master, 'n' * newtabwidth) text.configure(tabs=pixels) def set_indentation_params(self, ispythonsource, guess=True): if guess and ispythonsource: i = self.guess_indent() if 2 <= i <= 8: self.indentwidth = i if self.indentwidth != self.tabwidth: self.usetabs = False self.set_tabwidth(self.tabwidth) def smart_backspace_event(self, event): text = self.text first, last = self.get_selection_indices() if first and last: text.delete(first, last) text.mark_set('insert', first) return 'break' chars = text.get('insert linestart', 'insert') if chars == '': if text.compare('insert', '>', '1.0'): text.delete('insert-1c') else: text.bell() return 'break' if chars[-1] not in ' \t': text.delete('insert-1c') return 'break' tabwidth = self.tabwidth have = len(chars.expandtabs(tabwidth)) want = (have - 1) // self.indentwidth * self.indentwidth last_line_of_prompt = sys.ps1.split('\n')[-1] ncharsdeleted = 0 while 1: if chars == last_line_of_prompt: break chars = chars[:-1] ncharsdeleted = ncharsdeleted + 1 have = len(chars.expandtabs(tabwidth)) if have <= want or chars[-1] not in ' \t': break text.undo_block_start() text.delete('insert-%dc' % ncharsdeleted, 'insert') if have < want: text.insert('insert', ' ' * (want - have)) text.undo_block_stop() return 'break' def smart_indent_event(self, event): text = self.text first, last = self.get_selection_indices() text.undo_block_start() try: if first and last: if index2line(first) != index2line(last): return self.indent_region_event(event) text.delete(first, last) text.mark_set('insert', first) prefix = text.get('insert linestart', 'insert') raw, effective = classifyws(prefix, self.tabwidth) if raw == len(prefix): self.reindent_to(effective + self.indentwidth) else: if self.usetabs: pad = '\t' else: effective = len(prefix.expandtabs(self.tabwidth)) n = self.indentwidth pad = ' ' * (n - effective % n) text.insert('insert', pad) text.see('insert') return 'break' finally: text.undo_block_stop() def newline_and_indent_event(self, event): text = self.text first, last = self.get_selection_indices() text.undo_block_start() try: if first and last: text.delete(first, last) text.mark_set('insert', first) line = text.get('insert linestart', 'insert') i, n = 0, len(line) while i < n and line[i] in ' \t': i = i + 1 if i == n: text.insert('insert linestart', '\n') return 'break' indent = line[:i] i = 0 last_line_of_prompt = sys.ps1.split('\n')[-1] while line and line[-1] in ' \t' and line != last_line_of_prompt: line = line[:-1] i = i + 1 if i: text.delete('insert - %d chars' % i, 'insert') while text.get('insert') in ' \t': text.delete('insert') text.insert('insert', '\n') lno = index2line(text.index('insert')) y = PyParse.Parser(self.indentwidth, self.tabwidth) if not self.context_use_ps1: for context in self.num_context_lines: startat = max(lno - context, 1) startatindex = repr(startat) + '.0' rawtext = text.get(startatindex, 'insert') y.set_str(rawtext) bod = y.find_good_parse_start(self.context_use_ps1, self._build_char_in_string_func(startatindex)) if bod is not None or startat == 1: break y.set_lo(bod or 0) else: r = text.tag_prevrange('console', 'insert') if r: startatindex = r[1] else: startatindex = '1.0' rawtext = text.get(startatindex, 'insert') y.set_str(rawtext) y.set_lo(0) c = y.get_continuation_type() if c != PyParse.C_NONE: if c == PyParse.C_STRING_FIRST_LINE: pass elif c == PyParse.C_STRING_NEXT_LINES: text.insert('insert', indent) elif c == PyParse.C_BRACKET: self.reindent_to(y.compute_bracket_indent()) elif c == PyParse.C_BACKSLASH: if y.get_num_lines_in_stmt() > 1: text.insert('insert', indent) else: self.reindent_to(y.compute_backslash_indent()) return 'break' indent = y.get_base_indent_string() text.insert('insert', indent) if y.is_block_opener(): self.smart_indent_event(event) elif indent and y.is_block_closer(): self.smart_backspace_event(event) return 'break' finally: text.see('insert') text.undo_block_stop() return def _build_char_in_string_func(self, startindex): def inner(offset, _startindex=startindex, _icis=self.is_char_in_string): return _icis(_startindex + '+%dc' % offset) return inner def indent_region_event(self, event): head, tail, chars, lines = self.get_region() for pos in range(len(lines)): line = lines[pos] if line: raw, effective = classifyws(line, self.tabwidth) effective = effective + self.indentwidth lines[pos] = self._make_blanks(effective) + line[raw:] self.set_region(head, tail, chars, lines) return 'break' def dedent_region_event(self, event): head, tail, chars, lines = self.get_region() for pos in range(len(lines)): line = lines[pos] if line: raw, effective = classifyws(line, self.tabwidth) effective = max(effective - self.indentwidth, 0) lines[pos] = self._make_blanks(effective) + line[raw:] self.set_region(head, tail, chars, lines) return 'break' def comment_region_event(self, event): head, tail, chars, lines = self.get_region() for pos in range(len(lines) - 1): line = lines[pos] lines[pos] = '##' + line self.set_region(head, tail, chars, lines) def uncomment_region_event(self, event): head, tail, chars, lines = self.get_region() for pos in range(len(lines)): line = lines[pos] if not line: continue if line[:2] == '##': line = line[2:] elif line[:1] == '#': line = line[1:] lines[pos] = line self.set_region(head, tail, chars, lines) def tabify_region_event(self, event): head, tail, chars, lines = self.get_region() tabwidth = self._asktabwidth() for pos in range(len(lines)): line = lines[pos] if line: raw, effective = classifyws(line, tabwidth) ntabs, nspaces = divmod(effective, tabwidth) lines[pos] = '\t' * ntabs + ' ' * nspaces + line[raw:] self.set_region(head, tail, chars, lines) def untabify_region_event(self, event): head, tail, chars, lines = self.get_region() tabwidth = self._asktabwidth() for pos in range(len(lines)): lines[pos] = lines[pos].expandtabs(tabwidth) self.set_region(head, tail, chars, lines) def toggle_tabs_event(self, event): if self.askyesno('Toggle tabs', 'Turn tabs ' + ('on', 'off')[self.usetabs] + '?\nIndent width ' + ('will be', 'remains at')[self.usetabs] + ' 8.' + '\n Note: a tab is always 8 columns', parent=self.text): self.usetabs = not self.usetabs self.indentwidth = 8 return 'break' def change_indentwidth_event(self, event): new = self.askinteger('Indent width', 'New indent width (2-16)\n(Always use 8 when using tabs)', parent=self.text, initialvalue=self.indentwidth, minvalue=2, maxvalue=16) if new and new != self.indentwidth and not self.usetabs: self.indentwidth = new return 'break' def get_region(self): text = self.text first, last = self.get_selection_indices() if first and last: head = text.index(first + ' linestart') tail = text.index(last + '-1c lineend +1c') else: head = text.index('insert linestart') tail = text.index('insert lineend +1c') chars = text.get(head, tail) lines = chars.split('\n') return ( head, tail, chars, lines) def set_region(self, head, tail, chars, lines): text = self.text newchars = '\n'.join(lines) if newchars == chars: text.bell() return text.tag_remove('sel', '1.0', 'end') text.mark_set('insert', head) text.undo_block_start() text.delete(head, tail) text.insert(head, newchars) text.undo_block_stop() text.tag_add('sel', head, 'insert') def _make_blanks(self, n): if self.usetabs: ntabs, nspaces = divmod(n, self.tabwidth) return '\t' * ntabs + ' ' * nspaces else: return ' ' * n def reindent_to(self, column): text = self.text text.undo_block_start() if text.compare('insert linestart', '!=', 'insert'): text.delete('insert linestart', 'insert') if column: text.insert('insert', self._make_blanks(column)) text.undo_block_stop() def _asktabwidth(self): return self.askinteger('Tab width', 'Columns per tab? (2-16)', parent=self.text, initialvalue=self.indentwidth, minvalue=2, maxvalue=16) or self.tabwidth def guess_indent(self): opener, indented = IndentSearcher(self.text, self.tabwidth).run() if opener and indented: raw, indentsmall = classifyws(opener, self.tabwidth) raw, indentlarge = classifyws(indented, self.tabwidth) else: indentsmall = indentlarge = 0 return indentlarge - indentsmall
class ScriptBinding: menudefs = [ ('run', [ None, ('Check Module', '<<check-module>>'), ('Run Module', '<<run-module>>'), ]), ] def __init__(self, editwin): self.editwin = editwin # Provide instance variables referenced by Debugger # XXX This should be done differently self.flist = self.editwin.flist self.root = self.editwin.root if macosxSupport.runningAsOSXApp(): self.editwin.text_frame.bind('<<run-module-event-2>>', self._run_module_event) def check_module_event(self, event): filename = self.getfilename() if not filename: return 'break' if not self.checksyntax(filename): return 'break' if not self.tabnanny(filename): return 'break' def tabnanny(self, filename): f = open(filename, 'r') try: tabnanny.process_tokens(tokenize.generate_tokens(f.readline)) except tokenize.TokenError as msg: msgtxt, (lineno, start) = msg self.editwin.gotoline(lineno) self.errorbox("Tabnanny Tokenizing Error", "Token Error: %s" % msgtxt) return False except tabnanny.NannyNag as nag: # The error messages from tabnanny are too confusing... self.editwin.gotoline(nag.get_lineno()) self.errorbox("Tab/space error", indent_message) return False return True def checksyntax(self, filename): self.shell = shell = self.flist.open_shell() saved_stream = shell.get_warning_stream() shell.set_warning_stream(shell.stderr) with open(filename, 'r') as f: source = f.read() if '\r' in source: source = re.sub(r"\r\n", "\n", source) source = re.sub(r"\r", "\n", source) if source and source[-1] != '\n': source = source + '\n' text = self.editwin.text text.tag_remove("ERROR", "1.0", "end") try: try: # If successful, return the compiled code return compile(source, filename, "exec") except (SyntaxError, OverflowError, ValueError) as err: try: msg, (errorfilename, lineno, offset, line) = err if not errorfilename: err.args = msg, (filename, lineno, offset, line) err.filename = filename self.colorize_syntax_error(msg, lineno, offset) except: msg = "*** " + str(err) self.errorbox("Syntax error", "There's an error in your program:\n" + msg) return False finally: shell.set_warning_stream(saved_stream) def colorize_syntax_error(self, msg, lineno, offset): text = self.editwin.text pos = "0.0 + %d lines + %d chars" % (lineno - 1, offset - 1) text.tag_add("ERROR", pos) char = text.get(pos) if char and char in IDENTCHARS: text.tag_add("ERROR", pos + " wordstart", pos) if '\n' == text.get(pos): # error at line end text.mark_set("insert", pos) else: text.mark_set("insert", pos + "+1c") text.see(pos) def run_module_event(self, event): """Run the module after setting up the environment. First check the syntax. If OK, make sure the shell is active and then transfer the arguments, set the run environment's working directory to the directory of the module being executed and also add that directory to its sys.path if not already included. """ filename = self.getfilename() if not filename: return 'break' code = self.checksyntax(filename) if not code: return 'break' if not self.tabnanny(filename): return 'break' interp = self.shell.interp if PyShell.use_subprocess: interp.restart_subprocess(with_cwd=False) dirname = os.path.dirname(filename) # XXX Too often this discards arguments the user just set... interp.runcommand("""if 1: __file__ = {filename!r} import sys as _sys from os.path import basename as _basename if (not _sys.argv or _basename(_sys.argv[0]) != _basename(__file__)): _sys.argv = [__file__] import os as _os _os.chdir({dirname!r}) del _sys, _basename, _os \n""".format(filename=filename, dirname=dirname)) interp.prepend_syspath(filename) # XXX KBK 03Jul04 When run w/o subprocess, runtime warnings still # go to __stderr__. With subprocess, they go to the shell. # Need to change streams in PyShell.ModifiedInterpreter. interp.runcode(code) return 'break' if macosxSupport.runningAsOSXApp(): # Tk-Cocoa in MacOSX is broken until at least # Tk 8.5.9, and without this rather # crude workaround IDLE would hang when a user # tries to run a module using the keyboard shortcut # (the menu item works fine). _run_module_event = run_module_event def run_module_event(self, event): self.editwin.text_frame.after( 200, lambda: self.editwin.text_frame.event_generate( '<<run-module-event-2>>')) return 'break' def getfilename(self): """Get source filename. If not saved, offer to save (or create) file The debugger requires a source file. Make sure there is one, and that the current version of the source buffer has been saved. If the user declines to save or cancels the Save As dialog, return None. If the user has configured IDLE for Autosave, the file will be silently saved if it already exists and is dirty. """ filename = self.editwin.io.filename if not self.editwin.get_saved(): autosave = idleConf.GetOption('main', 'General', 'autosave', type='bool') if autosave and filename: self.editwin.io.save(None) else: confirm = self.ask_save_dialog() self.editwin.text.focus_set() if confirm: self.editwin.io.save(None) filename = self.editwin.io.filename else: filename = None return filename def ask_save_dialog(self): msg = "Source Must Be Saved\n" + 5 * ' ' + "OK to Save?" confirm = tkMessageBox.askokcancel(title="Save Before Run or Check", message=msg, default=tkMessageBox.OK, master=self.editwin.text) return confirm def errorbox(self, title, message): # XXX This should really be a function of EditorWindow... tkMessageBox.showerror(title, message, master=self.editwin.text) self.editwin.text.focus_set()
def initialise(): import sys global menudefs global default_keydefs if menudefs is not None: return menudefs = [ # underscore prefixes character to underscore ('file', [ ('Load From...', '<<load-from>>'), ('Revert', '<<revert>>'), None, ('_Save', '<<save-window>>'), #('Save _As...', '<<save-window-as-file>>'), ('Save Cop_y As...', '<<save-copy-of-window-as-file>>'), None, ('Prin_t Window', '<<print-window>>'), None, ('_Close', '<<close-window>>'), ('E_xit', '<<close-all-windows>>'), ]), ('edit', [ ('_Undo', '<<undo>>'), ('_Redo', '<<redo>>'), None, ('Cu_t', '<<cut>>'), ('_Copy', '<<copy>>'), ('_Paste', '<<paste>>'), ('Select _All', '<<select-all>>'), None, ('_Find...', '<<find>>'), ('Find A_gain', '<<find-again>>'), ('Find _Selection', '<<find-selection>>'), ('Find in Files...', '<<find-in-files>>'), ('R_eplace...', '<<replace>>'), ('Go to _Line', '<<goto-line>>'), ]), ('format', [ ('_Indent Region', '<<indent-region>>'), ('_Dedent Region', '<<dedent-region>>'), ('Comment _Out Region', '<<comment-region>>'), ('U_ncomment Region', '<<uncomment-region>>'), ('Tabify Region', '<<tabify-region>>'), ('Untabify Region', '<<untabify-region>>'), ('Toggle Tabs', '<<toggle-tabs>>'), ('New Indent Width', '<<change-indentwidth>>'), ]), ('options', [ ('_Configure IDLE...', '<<open-config-dialog>>'), None, ]), ("check", [ ("Check F5", '<<check>>') ]), ("online", [ ("Login", '<<login>>'), ("Logout", '<<logout>>'), ("Change Password", '<<change_password>>'), None, ("Upload Problem Answer", '<<upload_answer>>'), ("Download Problem Answer", '<<download_answer>>'), None, ("Submit Answer F6", '<<submit_answer>>'), ("Show Submissions", '<<show_submit>>') ]), ('help', [ ('_About IDLE', '<<about-idle>>'), None, ('_IDLE Help', '<<help>>'), ('Python _Docs', '<<python-docs>>'), None, ('About _Tutor', '<<about-tutor>>'), ('Tutor Help', '<<help-tutor>>'), ]), ] if macosxSupport.runningAsOSXApp(): # Running as a proper MacOS application bundle. This block restructures # the menus a little to make them conform better to the HIG. quitItem = menudefs[0][1][-1] closeItem = menudefs[0][1][-2] # Remove the last 3 items of the file menu: a separator, close window and # quit. Close window will be reinserted just above the save item, where # it should be according to the HIG. Quit is in the application menu. del menudefs[0][1][-3:] menudefs[0][1].insert(6, closeItem) # Remove the 'About' entry from the help menu, it is in the application # menu del menudefs[-1][1][0:2] menudefs.insert(0, ('application', [ ('About IDLE', '<<about-idle>>'), None, ('_Preferences....', '<<open-config-dialog>>'), ])) default_keydefs = idleConf.GetCurrentKeySet()
def initialise(): import sys global menudefs global default_keydefs if menudefs is not None: return menudefs = [ # underscore prefixes character to underscore ( 'file', [ ('Load From...', '<<load-from>>'), ('Revert', '<<revert>>'), None, ('_Save', '<<save-window>>'), #('Save _As...', '<<save-window-as-file>>'), ('Save Cop_y As...', '<<save-copy-of-window-as-file>>'), None, ('Prin_t Window', '<<print-window>>'), None, ('_Close', '<<close-window>>'), ('E_xit', '<<close-all-windows>>'), ]), ('edit', [ ('_Undo', '<<undo>>'), ('_Redo', '<<redo>>'), None, ('Cu_t', '<<cut>>'), ('_Copy', '<<copy>>'), ('_Paste', '<<paste>>'), ('Select _All', '<<select-all>>'), None, ('_Find...', '<<find>>'), ('Find A_gain', '<<find-again>>'), ('Find _Selection', '<<find-selection>>'), ('Find in Files...', '<<find-in-files>>'), ('R_eplace...', '<<replace>>'), ('Go to _Line', '<<goto-line>>'), ]), ('format', [ ('_Indent Region', '<<indent-region>>'), ('_Dedent Region', '<<dedent-region>>'), ('Comment _Out Region', '<<comment-region>>'), ('U_ncomment Region', '<<uncomment-region>>'), ('Tabify Region', '<<tabify-region>>'), ('Untabify Region', '<<untabify-region>>'), ('Toggle Tabs', '<<toggle-tabs>>'), ('New Indent Width', '<<change-indentwidth>>'), ]), ('options', [ ('_Configure IDLE...', '<<open-config-dialog>>'), None, ]), ("check", [("Check F5", '<<check>>')]), ("online", [("Login", '<<login>>'), ("Logout", '<<logout>>'), ("Change Password", '<<change_password>>'), None, ("Upload Problem Answer", '<<upload_answer>>'), ("Download Problem Answer", '<<download_answer>>'), None, ("Submit Answer F6", '<<submit_answer>>'), ("Show Submissions", '<<show_submit>>')]), ('help', [ ('_About IDLE', '<<about-idle>>'), None, ('_IDLE Help', '<<help>>'), ('Python _Docs', '<<python-docs>>'), None, ('About _Tutor', '<<about-tutor>>'), ('Tutor Help', '<<help-tutor>>'), ]), ] if macosxSupport.runningAsOSXApp(): # Running as a proper MacOS application bundle. This block restructures # the menus a little to make them conform better to the HIG. quitItem = menudefs[0][1][-1] closeItem = menudefs[0][1][-2] # Remove the last 3 items of the file menu: a separator, close window and # quit. Close window will be reinserted just above the save item, where # it should be according to the HIG. Quit is in the application menu. del menudefs[0][1][-3:] menudefs[0][1].insert(6, closeItem) # Remove the 'About' entry from the help menu, it is in the application # menu del menudefs[-1][1][0:2] menudefs.insert(0, ('application', [ ('About IDLE', '<<about-idle>>'), None, ('_Preferences....', '<<open-config-dialog>>'), ])) default_keydefs = idleConf.GetCurrentKeySet()