diff -r 000000000000 -r ca70ae20a155 src/extras/pyrepl/socket_keymap.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/extras/pyrepl/socket_keymap.py Tue Feb 16 10:07:05 2010 +0530 @@ -0,0 +1,250 @@ +# Copyright 2000-2004 Michael Hudson mwh@python.net +# +# Portions Copyright (c) 2005 Nokia Corporation +# +# All Rights Reserved +# +# +# Permission to use, copy, modify, and distribute this software and +# its documentation for any purpose is hereby granted without fee, +# provided that the above copyright notice appear in all copies and +# that both that copyright notice and this permission notice appear in +# supporting documentation. +# +# THE AUTHOR MICHAEL HUDSON DISCLAIMS ALL WARRANTIES WITH REGARD TO +# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +# AND FITNESS, IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, +# INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER +# RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +# CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +# CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +# keyspec parsing for a pygame console. currently this is simply copy +# n' change from the unix (ie. trad terminal) variant; probably some +# refactoring will happen when I work out how it will work best. + +# A key is represented as *either* + +# a) a (keycode, meta, ctrl) sequence (used for special keys such as +# f1, the up arrow key, etc) +# b) a (unichar, meta, ctrl) sequence (used for printable chars) + +# Because we allow keystokes like '\\C-xu', I'll use the same trick as +# the unix keymap module uses. + +# '\\C-a' --> (K_a, 0, 1) + +# XXX it's actually possible to test this module, so it should have a +# XXX test suite. + +import ascii + +_escapes = { + '\\': K_BACKSLASH, + "'" : K_QUOTE, + '"' : K_QUOTEDBL, +# 'a' : '\a', + 'b' : K_BACKSLASH, + 'e' : K_ESCAPE, +# 'f' : '\f', + 'n' : K_RETURN, + 'r' : K_RETURN, + 't' : K_TAB, +# 'v' : '\v' + } + +_keynames = { + 'backspace' : K_BACKSPACE, + 'delete' : K_DELETE, + 'down' : K_DOWN, + 'end' : K_END, + 'enter' : K_KP_ENTER, + 'escape' : K_ESCAPE, + 'f1' : K_F1, 'f2' : K_F2, 'f3' : K_F3, 'f4' : K_F4, + 'f5' : K_F5, 'f6' : K_F6, 'f7' : K_F7, 'f8' : K_F8, + 'f9' : K_F9, 'f10': K_F10,'f11': K_F11,'f12': K_F12, + 'f13': K_F13,'f14': K_F14,'f15': K_F15, + 'home' : K_HOME, + 'insert' : K_INSERT, + 'left' : K_LEFT, + 'pgdown' : K_PAGEDOWN, 'page down' : K_PAGEDOWN, + 'pgup' : K_PAGEUP, 'page up' : K_PAGEUP, + 'return' : K_RETURN, + 'right' : K_RIGHT, + 'space' : K_SPACE, + 'tab' : K_TAB, + 'up' : K_UP, + } + +class KeySpecError(Exception): + pass + +def _parse_key1(key, s): + ctrl = 0 + meta = 0 + ret = '' + while not ret and s < len(key): + if key[s] == '\\': + c = key[s+1].lower() + if _escapes.has_key(c): + ret = _escapes[c] + s += 2 + elif c == "c": + if key[s + 2] != '-': + raise KeySpecError, \ + "\\C must be followed by `-' (char %d of %s)"%( + s + 2, repr(key)) + if ctrl: + raise KeySpecError, "doubled \\C- (char %d of %s)"%( + s + 1, repr(key)) + ctrl = 1 + s += 3 + elif c == "m": + if key[s + 2] != '-': + raise KeySpecError, \ + "\\M must be followed by `-' (char %d of %s)"%( + s + 2, repr(key)) + if meta: + raise KeySpecError, "doubled \\M- (char %d of %s)"%( + s + 1, repr(key)) + meta = 1 + s += 3 + elif c.isdigit(): + n = key[s+1:s+4] + ret = chr(int(n, 8)) + s += 4 + elif c == 'x': + n = key[s+2:s+4] + ret = chr(int(n, 16)) + s += 4 + elif c == '<': + t = key.find('>', s) + if t == -1: + raise KeySpecError, \ + "unterminated \\< starting at char %d of %s"%( + s + 1, repr(key)) + try: + ret = _keynames[key[s+2:t].lower()] + s = t + 1 + except KeyError: + raise KeySpecError, \ + "unrecognised keyname `%s' at char %d of %s"%( + key[s+2:t], s + 2, repr(key)) + if ret is None: + return None, s + else: + raise KeySpecError, \ + "unknown backslash escape %s at char %d of %s"%( + `c`, s + 2, repr(key)) + else: + if ctrl: + ret = unicode(ascii.ctrl(key[s])) + else: + ret = unicode(key[s]) + s += 1 + return (ret, meta, ctrl), s + +def parse_keys(key): + s = 0 + r = [] + while s < len(key): + k, s = _parse_key1(key, s) + if k is None: + return None + r.append(k) + return tuple(r) + +def _compile_keymap(keymap): + r = {} + for key, value in keymap.items(): + r.setdefault(key[0], {})[key[1:]] = value + for key, value in r.items(): + if value.has_key(()): + if len(value) <> 1: + raise KeySpecError, \ + "key definitions for %s clash"%(value.values(),) + else: + r[key] = value[()] + else: + r[key] = _compile_keymap(value) + return r + +def compile_keymap(keymap): + r = {} + for key, value in keymap: + k = parse_keys(key) + if value is None and r.has_key(k): + del r[k] + if k is not None: + r[k] = value + return _compile_keymap(r) + +def keyname(key): + longest_match = '' + longest_match_name = '' + for name, keyseq in keyset.items(): + if keyseq and key.startswith(keyseq) and \ + len(keyseq) > len(longest_match): + longest_match = keyseq + longest_match_name = name + if len(longest_match) > 0: + return longest_match_name, len(longest_match) + else: + return None, 0 + +_unescapes = {'\r':'\\r', '\n':'\\n', '\177':'^?'} + +#for k,v in _escapes.items(): +# _unescapes[v] = k + +def unparse_key(keyseq): + if not keyseq: + return '' + name, s = keyname(keyseq) + if name: + if name <> 'escape' or s == len(keyseq): + return '\\<' + name + '>' + unparse_key(keyseq[s:]) + else: + return '\\M-' + unparse_key(keyseq[1:]) + else: + c = keyseq[0] + r = keyseq[1:] + if c == '\\': + p = '\\\\' + elif _unescapes.has_key(c): + p = _unescapes[c] + elif ord(c) < ord(' '): + p = '\\C-%s'%(chr(ord(c)+96),) + elif ord(' ') <= ord(c) <= ord('~'): + p = c + else: + p = '\\%03o'%(ord(c),) + return p + unparse_key(r) + +def _unparse_keyf(keyseq): + if not keyseq: + return [] + name, s = keyname(keyseq) + if name: + if name <> 'escape' or s == len(keyseq): + return [name] + _unparse_keyf(keyseq[s:]) + else: + rest = _unparse_keyf(keyseq[1:]) + return ['M-'+rest[0]] + rest[1:] + else: + c = keyseq[0] + r = keyseq[1:] + if c == '\\': + p = '\\' + elif _unescapes.has_key(c): + p = _unescapes[c] + elif ord(c) < ord(' '): + p = 'C-%s'%(chr(ord(c)+96),) + elif ord(' ') <= ord(c) <= ord('~'): + p = c + else: + p = '\\%03o'%(ord(c),) + return [p] + _unparse_keyf(r) + +def unparse_keyf(keyseq): + return " ".join(_unparse_keyf(keyseq))