""" Terminal Mode Extension Version: 0.5 Author: Roger D. Serwy serwy@illinois.edu Date: September 2008 This extension makes PyShell behave more like a terminal. Add these lines to config-extensions.def [Terminal] enable=1 enable_shell=1 enable_editor=0 """ from Tkinter import INSERT, END, SEL_FIRST, SEL_LAST, SEL from configHandler import idleConf import sys class Terminal: menudefs = [ ('options', [ ('!Terminal Mode', '<>'), ]),] def __init__(self, editwin): self.editwin = editwin self.text = self.editwin.text self.after = self.editwin.root.after self.oldundo = None self.enabled = idleConf.GetOption("extensions", "Terminal", "enabled", type="bool", default=True) self.editwin.setvar("<>", not not self.enabled) self.text.bind("<>", self.terminal_toggle) # this extension is loaded from EditorWindow.py, but before # PyShell.py makes its changes. Will use tk .after to make # changes if self.enabled: self.delay_init() def delay_init(self): # wait on the history object to be added to the window. This is # required for useful terminal-like behavior if hasattr(self.editwin, 'history') == True: self.terminal_mode_init() return self.after(100, self.delay_init) def terminal_toggle(self, event=None): self.enabled = not self.enabled self.editwin.setvar("<>", not not self.enabled) if self.enabled == False: self.terminal_mode_exit() else: self.terminal_mode_init() idleConf.SetOption("extensions", "Terminal", "enabled", '%s' % self.enabled) idleConf.SaveUserCfgFiles() def terminal_mode_init(self, event=None): # redefine some key bindings self.enabled = True text = self.editwin.text # up/down keys text.bind("<>", self.key_up_callback, '+') text.bind("<>", self.key_down_callback, '+') text.event_add("<>", "") text.event_add("<>", "") # page up/down keys text.bind("<>", self.key_pgup_callback, '+') text.bind("<>", self.key_pgdown_callback, '+') text.event_add("<>", "") text.event_add("<>", "") # home text.bind("<>", self.home_callback, '+') text.event_add("<>", "") # keep the cursor in the input area text.bind("<>", self.key_in_input, '+') text.event_add("<>", "") text.bind("<>", self.mouse_in_input, '+') text.event_add("<>", "") # need history for up/down keys self.history = self.editwin.history; # make sure cursor is in input self.key_in_input(event) def terminal_mode_exit(self, event=None): self.enabled = False text = self.editwin.text text.unbind("<>") text.unbind("<>") text.unbind("<>") text.unbind("<>") text.unbind("<>") text.unbind("<>") text.unbind("<>") def home_callback(self, event): text = self.text if self.text.compare("insert", "<", "iomark"): self.text.mark_set("insert", "iomark") return "break" if self.text.compare("iomark", "==", "insert"): return "break" return def mouse_in_input(self, event=None): # a mouse click on the window self.text.mark_set('insert', 'end-1c') #return "break" # don't return break, otherwise selection will not clear. def key_in_input(self, event=None): if self.text.compare('insert', '<=', 'iomark'): self.text.mark_set('insert', 'iomark') return "break" def key_pgup_callback(self, event): text = self.text text.yview_scroll(-1, 'pages') return "break" def key_pgdown_callback(self, event): text = self.text text.yview_scroll(1, 'pages') return "break" def history_ismember(self): """ if the current input is in the history, return true """ s = self.history._get_source('iomark', 'end-1c') for i in self.history.history: if i == s: return True return False def key_up_callback(self, event): s = self.text.get('iomark', 'end-1c') if s.find('\n') == -1: # single line input if self.text.compare('insert', '==', 'end-1c'): self.history.history_prev(event) return "break" else: self.text.mark_set('insert', 'end-1c') return "break" else: # multiline input if self.text.compare('insert', '==', 'end-1c'): if self.history_ismember() == True: self.history.history_prev(event) return "break" elif self.text.compare('insert linestart', '<=', 'iomark'): # don't leave the input area self.text.mark_set('insert', 'end-1c') return "break" def key_down_callback(self, event): s = self.text.get('iomark', 'end-1c') if s.find('\n') == -1: # single line input if self.text.compare('insert', '==', 'end-1c'): self.history.history_next(event) return "break" else: self.text.mark_set('insert', 'end-1c') return "break" else: # multiline input if self.text.compare('insert', '<', 'end-1c') and \ self.text.compare('insert lineend', '==', 'end-1c'): self.text.mark_set('insert', 'end-1c') return "break" if self.history_ismember() == True: if self.text.compare('insert', '==', 'end-1c'): self.history.history_next(event) return "break" elif self.text.compare('insert lineend', '==', 'end-1c'): return "break"