--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/extras/pyrepl/keymap.py Tue Feb 16 10:07:05 2010 +0530
@@ -0,0 +1,189 @@
+# Copyright 2000-2004 Michael Hudson mwh@python.net
+#
+# All Rights Reserved
+#
+# Portions Copyright (c) 2005 Nokia Corporation
+#
+# 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.
+
+"""
+functions for parsing keyspecs
+
+Support for turning keyspecs into appropriate sequences.
+
+pyrepl uses it's own bastardized keyspec format, which is meant to be
+a strict superset of readline's \"KEYSEQ\" format (which is to say
+that if you can come up with a spec readline accepts that this
+doesn't, you've found a bug and should tell me about it).
+
+Note that this is the `\\C-o' style of readline keyspec, not the
+`Control-o' sort.
+
+A keyspec is a string representing a sequence of keypresses that can
+be bound to a command.
+
+All characters other than the backslash represent themselves. In the
+traditional manner, a backslash introduces a escape sequence.
+
+The extension to readline is that the sequence \\<KEY> denotes the
+sequence of charaters produced by hitting KEY.
+
+Examples:
+
+`a' - what you get when you hit the `a' key
+`\\EOA' - Escape - O - A (up, on my terminal)
+`\\<UP>' - the up arrow key
+`\\<up>' - ditto (keynames are case insensitive)
+`\\C-o', `\\c-o' - control-o
+`\\M-.' - meta-period
+`\\E.' - ditto (that's how meta works for pyrepl)
+`\\<tab>', `\\<TAB>', `\\t', `\\011', '\\x09', '\\X09', '\\C-i', '\\C-I'
+ - all of these are the tab character. Can you think of any more?
+"""
+
+import ascii
+
+_escapes = {
+ '\\':'\\',
+ "'":"'",
+ '"':'"',
+ 'a':'\a',
+ 'b':'\h',
+ 'e':'\033',
+ 'f':'\f',
+ 'n':'\n',
+ 'r':'\r',
+ 't':'\t',
+ 'v':'\v'
+ }
+
+_keynames = {
+ 'backspace': 'backspace',
+ 'delete': 'delete',
+ 'down': 'down',
+ 'end': 'end',
+ 'enter': '\r',
+ 'escape': '\033',
+ 'f1' : 'f1', 'f2' : 'f2', 'f3' : 'f3', 'f4' : 'f4',
+ 'f5' : 'f5', 'f6' : 'f6', 'f7' : 'f7', 'f8' : 'f8',
+ 'f9' : 'f9', 'f10': 'f10', 'f11': 'f11', 'f12': 'f12',
+ 'f13': 'f13', 'f14': 'f14', 'f15': 'f15', 'f16': 'f16',
+ 'f17': 'f17', 'f18': 'f18', 'f19': 'f19', 'f20': 'f20',
+ 'home': 'home',
+ 'insert': 'insert',
+ 'left': 'left',
+ 'page down': 'page down',
+ 'page up': 'page up',
+# 'return': 'enter',
+ 'return': '\r',
+ 'right': 'right',
+ 'space': ' ',
+ 'tab': '\t',
+ 'up': '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))
+ ret = key[s+2:t].lower()
+ if ret not in _keynames:
+ raise KeySpecError, \
+ "unrecognised keyname `%s' at char %d of %s"%(
+ ret, s + 2, repr(key))
+ ret = _keynames[ret]
+ s = t + 1
+ else:
+ raise KeySpecError, \
+ "unknown backslash escape %s at char %d of %s"%(
+ `c`, s + 2, repr(key))
+ else:
+ ret = key[s]
+ s += 1
+ if ctrl:
+ if len(ret) > 1:
+ raise KeySpecError, "\\C- must be followed by a character"
+ ret = ascii.ctrl(ret)
+ if meta:
+ ret = ['\033', ret]
+ else:
+ ret = [ret]
+ return ret, s
+
+def parse_keys(key):
+ s = 0
+ r = []
+ while s < len(key):
+ k, s = _parse_key1(key, s)
+ r.extend(k)
+ return r
+
+def compile_keymap(keymap, empty=''):
+ r = {}
+ for key, value in keymap.items():
+ r.setdefault(key[0], {})[key[1:]] = value
+ for key, value in r.items():
+ if empty in value:
+ if len(value) <> 1:
+ raise KeySpecError, \
+ "key definitions for %s clash"%(value.values(),)
+ else:
+ r[key] = value[empty]
+ else:
+ r[key] = compile_keymap(value, empty)
+ return r