From 89b5a62de11a9979796b84d9ab74de3d12309b04 Mon Sep 17 00:00:00 2001 From: jstenar <> Date: Mon, 11 Sep 2006 20:00:23 +0000 Subject: [PATCH] pyreadline-refactor: Merge ansi patch and tab patch from trunk. --- doc/ChangeLog | 9 ++ pyreadline/console/ansi.py | 175 +++++++++++++++++++++++++++++++ pyreadline/console/console.py | 21 +++- pyreadline/error.py | 14 +++ pyreadline/keysyms/common.py | 14 ++- pyreadline/lineeditor/history.py | 44 ++++---- pyreadline/lineeditor/lineobj.py | 2 +- pyreadline/logger.py | 21 +++- pyreadline/logserver.py | 60 +++++++++++ pyreadline/modes/basemode.py | 8 ++ pyreadline/modes/emacs.py | 68 +++++++++--- pyreadline/rlmain.py | 12 +-- 12 files changed, 398 insertions(+), 50 deletions(-) create mode 100644 pyreadline/console/ansi.py create mode 100644 pyreadline/error.py create mode 100644 pyreadline/logserver.py diff --git a/doc/ChangeLog b/doc/ChangeLog index 38e818d..cd6a147 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,12 @@ +2006-09-11 Jörgen Stenarson + * Added logserver. Socket based server that can receive logmessage. + To be used when debugging keypresses, could be a security risk as a keyboard sniffer. + * Added log_sock call to send logging to logserver + * Merging ANSI parsing from trunk + * Parsing escape sequence for up down key in parse_bind + * Merging bugfix for self_insert of tabs from trunk + * Add bindable function that prints keybindings + 2006-07-13 Jörgen Stenarson * Work to get selection between ironpython and cpython to work * Some editing works but there are issues with control keys for ironpython diff --git a/pyreadline/console/ansi.py b/pyreadline/console/ansi.py new file mode 100644 index 0000000..413e4b6 --- /dev/null +++ b/pyreadline/console/ansi.py @@ -0,0 +1,175 @@ +# -*- coding: ISO-8859-1 -*- +import re,sys,os,pprint +pprint=pprint.pprint + +terminal_escape = re.compile('(\001?\033\\[[0-9;]*m\002?)') +escape_parts = re.compile('\001?\033\\[([0-9;]*)m\002?') + + +class AnsiState(object): + def __init__(self,bold=False,inverse=False,color="white",background="black",backgroundbold=False): + self.bold=bold + self.inverse=inverse + self.color=color + self.background=background + self.backgroundbold=backgroundbold + + trtable={"black":0,"red":4,"green":2,"yellow":6,"blue":1,"magenta":5,"cyan":3,"white":7} + revtable=dict(zip(trtable.values(),trtable.keys())) + def get_winattr(self): + attr=0 + if self.bold: + attr|=0x0008 + if self.backgroundbold: + attr|=0x0080 + if self.inverse: + attr|=0x4000 + attr|=self.trtable[self.color] + attr|=(self.trtable[self.background]<<4) + return attr + + def set_winattr(self,attr): + self.bold=bool(attr&0x0008) + self.backgroundbold=bool(attr&0x0080) + self.inverse=bool(attr&0x4000) + self.color=self.revtable[attr&0x0007] + self.background=self.revtable[(attr&0x0070)>>4] + + winattr=property(get_winattr,set_winattr) + def __repr__(self): + return 'AnsiState(bold=%s,inverse=%s,color=%9s,background=%9s,backgroundbold=%s)# 0x%x'%(self.bold, + self.inverse, + '"%s"'%self.color, + '"%s"'%self.background, + self.backgroundbold, + self.winattr) + + def copy(self): + x=AnsiState() + x.bold=self.bold + x.inverse=self.inverse + x.color=self.color + x.background=self.background + x.backgroundbold=self.backgroundbold + return x +defaultstate=AnsiState(False,False,"white") + +trtable={0:"black",1:"red",2:"green",3:"yellow",4:"blue",5:"magenta",6:"cyan",7:"white"} + +class AnsiWriter(object): + def __init__(self,default=defaultstate): + if isinstance(defaultstate,AnsiState): + self.defaultstate=default + else: + self.defaultstate=AnsiState() + self.defaultstate.winattr=defaultstate + + + def write_color(self,text, attr=None): + '''write text at current cursor position and interpret color escapes. + + return the number of characters written. + ''' + if isinstance(attr,AnsiState): + defaultstate=attr + elif attr is None: #use attribute form initial console + attr = self.defaultstate.copy() + else: + defaultstate=AnsiState() + defaultstate.winattr=attr + attr=defaultstate + chunks = terminal_escape.split(text) + n = 0 # count the characters we actually write, omitting the escapes + res=[] + for chunk in chunks: + m = escape_parts.match(chunk) + if m: + for part in m.group(1).split(";"): + if part == "0": # No text attribute + attr = self.defaultstate.copy() + elif part == "7": # switch on reverse + attr.inverse=True + elif part == "1": # switch on bold (i.e. intensify foreground color) + attr.bold=True + elif len(part) == 2 and "30" <= part <= "37": # set foreground color + attr.color = trtable[int(part)-30] + elif len(part) == 2 and "40" <= part <= "47": # set background color + attr.color = trtable[int(part)-40] + continue + n += len(chunk) + if True: + res.append((attr.copy(),chunk)) + return n,res + + def parse_color(self,text, attr=None): + n,res=self.write_color(text,attr) + return n,[attr.winattr for attr,text in res] + +def write_color(text,attr=None): + a=AnsiWriter(defaultstate) + return a.write_color(text,attr) + +def write_color_old( text, attr=None): + '''write text at current cursor position and interpret color escapes. + + return the number of characters written. + ''' + res=[] + chunks = terminal_escape.split(text) + n = 0 # count the characters we actually write, omitting the escapes + if attr is None:#use attribute from initial console + attr = 15 + for chunk in chunks: + m = escape_parts.match(chunk) + if m: + for part in m.group(1).split(";"): + if part == "0": # No text attribute + attr = 0 + elif part == "7": # switch on reverse + attr |= 0x4000 + if part == "1": # switch on bold (i.e. intensify foreground color) + attr |= 0x08 + elif len(part) == 2 and "30" <= part <= "37": # set foreground color + part = int(part)-30 + # we have to mirror bits + attr = (attr & ~0x07) | ((part & 0x1) << 2) | (part & 0x2) | ((part & 0x4) >> 2) + elif len(part) == 2 and "40" <= part <= "47": # set background color + part = int(part)-40 + # we have to mirror bits + attr = (attr & ~0x70) | ((part & 0x1) << 6) | ((part & 0x2) << 4) | ((part & 0x4) << 2) + # ignore blink, underline and anything we don't understand + continue + n += len(chunk) + if chunk: + res.append(("0x%x"%attr,chunk)) + return res + + +#trtable={0:"black",1:"red",2:"green",3:"yellow",4:"blue",5:"magenta",6:"cyan",7:"white"} + +if __name__=="__main__": + import startup + s="\033[0;31mred\033[0;32mgreen\033[0;33myellow\033[0;34mblue\033[0;35mmagenta\033[0;36mcyan\033[0;37mwhite\033[0m" + pprint (write_color(s)) + pprint (write_color_old(s)) + s="\033[1;31mred\033[1;32mgreen\033[1;33myellow\033[1;34mblue\033[1;35mmagenta\033[1;36mcyan\033[1;37mwhite\033[0m" + pprint (write_color(s)) + pprint (write_color_old(s)) + + s="\033[0;7;31mred\033[0;7;32mgreen\033[0;7;33myellow\033[0;7;34mblue\033[0;7;35mmagenta\033[0;7;36mcyan\033[0;7;37mwhite\033[0m" + pprint (write_color(s)) + pprint (write_color_old(s)) + s="\033[1;7;31mred\033[1;7;32mgreen\033[1;7;33myellow\033[1;7;34mblue\033[1;7;35mmagenta\033[1;7;36mcyan\033[1;7;37mwhite\033[0m" + pprint (write_color(s)) + pprint (write_color_old(s)) + + +if __name__=="__main__": + import console + + c=console.Console() + c.write_color("dhsjdhs") + c.write_color("\033[0;32mIn [\033[1;32m1\033[0;32m]:") + print + pprint (write_color("\033[0;32mIn [\033[1;32m1\033[0;32m]:")) + \ No newline at end of file diff --git a/pyreadline/console/console.py b/pyreadline/console/console.py index b789ba1..e2b30a4 100644 --- a/pyreadline/console/console.py +++ b/pyreadline/console/console.py @@ -16,7 +16,7 @@ This was modeled after the C extension of the same name by Fredrik Lundh. import sys import traceback import re -from pyreadline.logger import log +from pyreadline.logger import log,log_sock try: # I developed this with ctypes 0.6 @@ -27,6 +27,7 @@ except ImportError: # my code from pyreadline.keysyms import make_KeyPress +from pyreadline.console.ansi import AnsiState,AnsiWriter # some constants we need STD_INPUT_HANDLE = -10 @@ -183,6 +184,11 @@ class Console(object): self.GetConsoleScreenBufferInfo(self.hout, byref(info)) self.attr = info.wAttributes self.saveattr = info.wAttributes # remember the initial colors + + self.defaultstate=AnsiState() + self.defaultstate.winattr=info.wAttributes + self.ansiwriter=AnsiWriter(self.defaultstate) + background = self.attr & 0xf0 for escape in self.escape_to_color: if self.escape_to_color[escape] is not None: @@ -336,6 +342,17 @@ class Console(object): self.WriteConsoleA(self.hout, chunk, len(chunk), byref(junk), None) return n + def write_color(self, text, attr=None): + n,res= self.ansiwriter.write_color(text,attr) + junk = c_int(0) + for attr,chunk in res: + log(str(attr)) + log(str(chunk)) + self.SetConsoleTextAttribute(self.hout, attr.winattr) + self.WriteConsoleA(self.hout, chunk, len(chunk), byref(junk), None) + return n + + def write_plain(self, text, attr=None): '''write text at current cursor position.''' log('write("%s", %s)' %(text,attr)) @@ -453,6 +470,7 @@ class Console(object): status = self.ReadConsoleInputA(self.hin, byref(Cevent), 1, byref(count)) if status and count.value == 1: e = event(self, Cevent) + log_sock(str(e.keyinfo),"keypress") return e def getkeypress(self): @@ -469,6 +487,7 @@ class Console(object): return e elif e.type == 'KeyRelease' and e.keyinfo==(True, False, False, 83): log("getKeypress:%s,%s,%s"%(e.keyinfo,e.keycode,e.type)) +# log_sock(str(e)) return e def getchar(self): diff --git a/pyreadline/error.py b/pyreadline/error.py new file mode 100644 index 0000000..e7c3305 --- /dev/null +++ b/pyreadline/error.py @@ -0,0 +1,14 @@ +# -*- coding: utf-8 -*- +#***************************************************************************** +# Copyright (C) 2006 Jorgen Stenarson. +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#***************************************************************************** + + +class ReadlineError(Exception): + pass + +class GetSetError(ReadlineError): + pass diff --git a/pyreadline/keysyms/common.py b/pyreadline/keysyms/common.py index 444afeb..719fc11 100644 --- a/pyreadline/keysyms/common.py +++ b/pyreadline/keysyms/common.py @@ -29,6 +29,8 @@ validkey =set(['cancel', 'backspace', 'tab', 'clear', 'numpad8', 'numpad9', 'divide', 'multiply', 'add', 'subtract', 'vk_decimal']) +escape_sequence_to_special_key={"\\e[a":"up","\\e[b":"down","del":"delete"} + class KeyPress(object): def __init__(self,char="",shift=False,control=False,meta=False,keyname=""): if control or meta or shift: @@ -65,7 +67,9 @@ class KeyPress(object): def make_KeyPress_from_keydescr(keydescr): keyinfo=KeyPress() - + if len(keydescr)>2 and keydescr[:1]=='"' and keydescr[-1:]=='"': + keydescr=keydescr[1:-1] + while 1: lkeyname = keydescr.lower() if lkeyname.startswith('control-'): @@ -74,14 +78,14 @@ def make_KeyPress_from_keydescr(keydescr): elif lkeyname.startswith('ctrl-'): keyinfo.control = True keydescr = keydescr[5:] - elif keydescr.startswith('\\C-'): + elif keydescr.lower().startswith('\\c-'): keyinfo.control = True keydescr = keydescr[3:] - elif keydescr.startswith('\\M-'): + elif keydescr.lower().startswith('\\m-'): keyinfo.meta = True keydescr = keydescr[3:] - elif keydescr.startswith('\\e-'): - keydescr = "escape"+keydescr[3:] + elif keydescr in escape_sequence_to_special_key: + keydescr = escape_sequence_to_special_key[keydescr] elif lkeyname.startswith('meta-'): keyinfo.meta = True keydescr = keydescr[5:] diff --git a/pyreadline/lineeditor/history.py b/pyreadline/lineeditor/history.py index 4aadff4..bfe789e 100644 --- a/pyreadline/lineeditor/history.py +++ b/pyreadline/lineeditor/history.py @@ -21,6 +21,8 @@ import exceptions class EscapeHistory(exceptions.Exception): pass +from pyreadline.logger import log_sock + class LineHistory(object): def __init__(self): self.history=[] @@ -96,15 +98,19 @@ class LineHistory(object): self.history_cursor=len(self.history) current.set_line(self.history[-1].get_line_text()) - def reverse_search_history(self,searchfor): - res=[(idx,line) for idx,line in enumerate(self.history[self.history_cursor:0:-1]) if searchfor in line] + def reverse_search_history(self,searchfor,startpos=None): + if startpos is None: + startpos=self.history_cursor + res=[(idx,line) for idx,line in enumerate(self.history[startpos:0:-1]) if searchfor in line] if res: self.history_cursor-=res[0][0] return res[0][1].get_line_text() return "" - def forward_search_history(self,searchfor): - res=[(idx,line) for idx,line in enumerate(self.history[self.history_cursor:]) if searchfor in line] + def forward_search_history(self,searchfor,startpos=None): + if startpos is None: + startpos=self.history_cursor + res=[(idx,line) for idx,line in enumerate(self.history[startpos:]) if searchfor in line] if res: self.history_cursor+=res[0][0] return res[0][1].get_line_text() @@ -121,41 +127,41 @@ class LineHistory(object): pyreadline.rl._clear_after() event = c.getkeypress() - if event.keysym == 'BackSpace': + log_sock(str(event)) + + if event.keyinfo.keyname == 'backspace': if len(query) > 0: query = query[:-1] else: break elif event.char in string.letters + string.digits + string.punctuation + ' ': query += event.char - elif event.keysym == 'Return': + elif event.keyinfo.keyname == 'return': break else: pyreadline.rl._bell() - + log_sock(query) + res="" if query: - hc = self.history_cursor - 1 - while (direction < 0 and hc >= 0) or (direction > 0 and hc < len(self.history)): - if self.history[hc].startswith(query) >= 0: - current=self.history[hc] - self.history_cursor = hc - return - hc += direction + if direction==-1: + res=self.reverse_search_history(query) + else: - pyreadline.rl._bell() - - + res=self.forward_search_history(query) + log_sock(res) + return lineobj.ReadLineTextBuffer(res,point=0) + def non_incremental_reverse_search_history(self,current): # (M-p) '''Search backward starting at the current line and moving up through the history as necessary using a non-incremental search for a string supplied by the user.''' - self._non_i_search(-1,current) + return self._non_i_search(-1,current) def non_incremental_forward_search_history(self,current): # (M-n) '''Search forward starting at the current line and moving down through the the history as necessary using a non-incremental search for a string supplied by the user.''' - self._non_i_search(1,current) + return self._non_i_search(1,current) def _search(self, direction, partial): if (self.lastcommand != self.history_search_forward and diff --git a/pyreadline/lineeditor/lineobj.py b/pyreadline/lineeditor/lineobj.py index 2a05070..b1ceec6 100644 --- a/pyreadline/lineeditor/lineobj.py +++ b/pyreadline/lineeditor/lineobj.py @@ -223,7 +223,7 @@ class TextLine(object): def visible_line_width(self,position=Point): """Return the visible width of the text in line buffer up to position.""" - return len(self[:position].quoted_text()) + return len(self[:position].quoted_text())+self[:position].line_buffer.count("\t")*7 def quoted_text(self): quoted = [ quote_char(c) for c in self.line_buffer ] diff --git a/pyreadline/logger.py b/pyreadline/logger.py index 286989f..f11aac9 100644 --- a/pyreadline/logger.py +++ b/pyreadline/logger.py @@ -6,7 +6,7 @@ # the file COPYING, distributed as part of this software. #***************************************************************************** - +import socket _logfile=False def start_log(on,filename): @@ -20,3 +20,22 @@ def log(s): if _logfile: print >>_logfile, s _logfile.flush() + + +host="localhost" +port=8081 +logsocket=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) + +show_event=["keypress","bound_function"] +show_event=["bound_function"] + +def log_sock(s,event_type=None): + if event_type is None: + logsocket.sendto(s,(host,port)) + elif event_type in show_event: + logsocket.sendto(s,(host,port)) + else: + pass + + +log_sock("Starting pyreadline") \ No newline at end of file diff --git a/pyreadline/logserver.py b/pyreadline/logserver.py new file mode 100644 index 0000000..6b761b2 --- /dev/null +++ b/pyreadline/logserver.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +#***************************************************************************** +# Copyright (C) 2006 Jorgen Stenarson. +# +# Distributed under the terms of the BSD License. The full license is in +# the file COPYING, distributed as part of this software. +#***************************************************************************** +import socket + + +try: + import msvcrt +except ImportError: + msvcrt=None + print "problem" + + + +port =8081 + +s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM) + +s.bind(("",port)) +s.settimeout(0.05) + +print "Starting logserver on port:",port +print "Press q to quit logserver",port +singleline=False + + +def check_key(): + if msvcrt is None: + return False + else: + if msvcrt.kbhit()!=0: + q=msvcrt.getch() + + return q in "q" + else: + return False + + +while 1: + try: + data,addr=s.recvfrom(1024) + except socket.timeout: + if check_key(): + print "Quitting logserver" + break + else: + continue + if data.startswith("@@"): + continue + if singleline: + print "\r"," "*78,"\r",data,#,addr + else: + print data + + + diff --git a/pyreadline/modes/basemode.py b/pyreadline/modes/basemode.py index f3dde03..55b9b00 100644 --- a/pyreadline/modes/basemode.py +++ b/pyreadline/modes/basemode.py @@ -13,6 +13,7 @@ from pyreadline.keysyms.common import make_KeyPress_from_keydescr import pyreadline.lineeditor.lineobj as lineobj import pyreadline.lineeditor.history as history import pyreadline.clipboard as clipboard +from pyreadline.error import ReadlineError,GetSetError class BaseMode(object): mode="base" @@ -64,6 +65,10 @@ class BaseMode(object): enable_ipython_paste_for_paths=property(_g("enable_ipython_paste_for_paths")) _bell=property(_g("_bell")) _history=property(_g("_history")) + prompt_end_pos=property(_g("prompt_end_pos")) + prompt_begin_pos=property(_g("prompt_begin_pos")) + + rl_settings_to_string=property(_g("rl_settings_to_string")) def _readline_from_keyboard(self): raise NotImplementedError @@ -75,6 +80,9 @@ class BaseMode(object): def _bind_key(self, key, func): '''setup the mapping from key to call the function.''' + if type(func) != type(self._bind_key): + print "Trying to bind non method to keystroke:%s,%s"%(key,func) + raise PyreadlineError("Trying to bind non method to keystroke:%s,%s,%s,%s"%(key,func,type(func),type(self._bind_key))) keyinfo = make_KeyPress_from_keydescr(key.lower()).tuple() self.key_dispatch[keyinfo] = func diff --git a/pyreadline/modes/emacs.py b/pyreadline/modes/emacs.py index 38ebe16..d771961 100644 --- a/pyreadline/modes/emacs.py +++ b/pyreadline/modes/emacs.py @@ -8,11 +8,19 @@ #***************************************************************************** import os import pyreadline.logger as logger -from pyreadline.logger import log +from pyreadline.logger import log,log_sock +from pyreadline.lineeditor.lineobj import Point import pyreadline.lineeditor.lineobj as lineobj import pyreadline.lineeditor.history as history import basemode - +import string +def format(keyinfo): + if len(keyinfo[-1])!=1: + k=keyinfo+(-1,) + else: + k=keyinfo+(ord(keyinfo[-1]),) + + return "(%s,%s,%s,%s,%x)"%k class EmacsMode(basemode.BaseMode): mode="emacs" @@ -30,6 +38,8 @@ class EmacsMode(basemode.BaseMode): def _readline_from_keyboard(self): c=self.console + def nop(e): + pass while 1: self._update_line() event = c.getkeypress() @@ -39,12 +49,18 @@ class EmacsMode(basemode.BaseMode): event.keyinfo = (control, True, shift, code) #Process exit keys. Only exit on empty line - if event.keyinfo.tuple() in self.exit_dispatch: + keyinfo=event.keyinfo.tuple() + if keyinfo in self.exit_dispatch: if lineobj.EndOfLine(self.l_buffer) == 0: raise EOFError + if len(keyinfo[-1])>1: + default=nop + else: + default=self.self_insert + dispatch_func = self.key_dispatch.get(keyinfo,default) - dispatch_func = self.key_dispatch.get(event.keyinfo.tuple(),self.self_insert) - log("readline from keyboard:%s"%(event.keyinfo.tuple(),)) + log("readline from keyboard:%s,%s"%(keyinfo,dispatch_func)) + log_sock("%s|%s"%(format(keyinfo),dispatch_func.__name__)) r = None if dispatch_func: r = dispatch_func(event) @@ -118,11 +134,12 @@ class EmacsMode(basemode.BaseMode): def _i_search(self, searchfun, direction, init_event): c = self.console - line = self.get_line_buffer() + line = self.l_buffer.get_line_text() + log_sock(str(line)) query = '' if (self.previous_func != self.history_search_forward and self.previous_func != self.history_search_backward): - self.query = ''.join(self.line_buffer[0:self.point].get_line_text()) + self.query = ''.join(self.l_buffer[0:Point].get_line_text()) hc_start = self._history.history_cursor #+ direction while 1: x, y = self.prompt_end_pos @@ -137,24 +154,25 @@ class EmacsMode(basemode.BaseMode): self._clear_after() event = c.getkeypress() - if event.keysym == 'BackSpace': + if event.keyinfo.keyname == 'backspace': + query = query[:-1] if len(query) > 0: - query = query[:-1] - self._history.history_cursor = hc_start + #self._history.history_cursor = hc_start #forces search to restart when search empty + line=searchfun(query) else: self._bell() + line="" #empty query means no search result elif event.char in string.letters + string.digits + string.punctuation + ' ': - self._history.history_cursor = hc_start + #self._history.history_cursor = hc_start query += event.char + line=searchfun(query) elif event.keyinfo == init_event.keyinfo: self._history.history_cursor += direction line=searchfun(query) - pass else: - if event.keysym != 'Return': + if event.keyinfo.keyname != 'return': self._bell() break - line=searchfun(query) px, py = self.prompt_begin_pos c.pos(0, py) @@ -177,13 +195,15 @@ class EmacsMode(basemode.BaseMode): '''Search backward starting at the current line and moving up through the history as necessary using a non-incremental search for a string supplied by the user.''' - self._history.non_incremental_reverse_search_history(self.l_buffer) + q=self._history.non_incremental_reverse_search_history(self.l_buffer) + self.l_buffer=q def non_incremental_forward_search_history(self, e): # (M-n) '''Search forward starting at the current line and moving down through the the history as necessary using a non-incremental search for a string supplied by the user.''' - self._history.non_incremental_reverse_search_history(self.l_buffer) + q=self._history.non_incremental_reverse_search_history(self.l_buffer) + self.l_buffer=q def history_search_forward(self, e): # () '''Search forward through the history for the string of characters @@ -487,6 +507,7 @@ class EmacsMode(basemode.BaseMode): self._bind_exit_key('Control-z') # I often accidentally hold the shift or control while typing space + self._bind_key('space', self.self_insert) self._bind_key('Shift-space', self.self_insert) self._bind_key('Control-space', self.self_insert) self._bind_key('Return', self.accept_line) @@ -540,6 +561,21 @@ class EmacsMode(basemode.BaseMode): self._bind_key("Shift-Control-Left", self.backward_word_extend_selection) self._bind_key("Shift-Home", self.beginning_of_line_extend_selection) self._bind_key("Shift-End", self.end_of_line_extend_selection) + self._bind_key("numpad0", self.self_insert) + self._bind_key("numpad1", self.self_insert) + self._bind_key("numpad2", self.self_insert) + self._bind_key("numpad3", self.self_insert) + self._bind_key("numpad4", self.self_insert) + self._bind_key("numpad5", self.self_insert) + self._bind_key("numpad6", self.self_insert) + self._bind_key("numpad7", self.self_insert) + self._bind_key("numpad8", self.self_insert) + self._bind_key("numpad9", self.self_insert) + self._bind_key("add", self.self_insert) + self._bind_key("subtract", self.self_insert) + self._bind_key("multiply", self.self_insert) + self._bind_key("divide", self.self_insert) + self._bind_key("vk_decimal", self.self_insert) # make it case insensitive def commonprefix(m): diff --git a/pyreadline/rlmain.py b/pyreadline/rlmain.py index 612d6fc..2f11238 100644 --- a/pyreadline/rlmain.py +++ b/pyreadline/rlmain.py @@ -20,6 +20,7 @@ import exceptions import clipboard,logger,console from logger import log +from error import ReadlineError,GetSetError from pyreadline.keysyms.common import make_KeyPress_from_keydescr import pyreadline.lineeditor.lineobj as lineobj @@ -32,14 +33,9 @@ def quote_char(c): if ord(c)>0: return c -class ReadlineError(exceptions.Exception): - pass - def inword(buffer,point): return buffer[point:point+1] in [A-Za-z0-9] -class GetSetError(ReadlineError): - pass class Readline(object): def __init__(self): @@ -245,7 +241,7 @@ class Readline(object): ## Internal functions - def rl_settings_to_string(self): + def rl_settings_to_string(self,e=None): out=["%-20s: %s"%("show all if ambigous",self.show_all_if_ambiguous)] out.append("%-20s: %s"%("mark_directories",self.mark_directories)) out.append("%-20s: %s"%("bell_style",self.bell_style)) @@ -253,7 +249,7 @@ class Readline(object): out.append("------------- key bindings ------------") tablepat="%-7s %-7s %-7s %-15s %-15s " out.append(tablepat%("Control","Meta","Shift","Keycode/char","Function")) - bindings=[(k[0],k[1],k[2],k[3],v.__name__)for k,v in self.mode.key_dispatch.iteritems()] + bindings=[(k[0],k[1],k[2],k[3],v.__name__) for k,v in self.mode.key_dispatch.iteritems()] #print self.mode.key_dispatch #bindings=[str(v) for k,v in self.mode.key_dispatch.iteritems()] bindings.sort() @@ -261,6 +257,8 @@ class Readline(object): pass # out.append(str(key)) out.append(tablepat%(key)) + if e: + print "\n".join(out) return out def _bell(self):