-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcustom_readline_bindings.py
More file actions
137 lines (111 loc) · 4.92 KB
/
custom_readline_bindings.py
File metadata and controls
137 lines (111 loc) · 4.92 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# ~/lib-py/custom_readline_bindings.py
#
# Custom Readline bindings, to be imported by the Python startup file.
#
# Example usage:
#
# import sys
# import readline
# import custom_readline_bindings
#
# for binding in custom_readline_bindings.get_bindings().iteritems():
# readline.parse_and_bind("%s: %s" % binding)
#
# print >> sys.stderr, 'Enabled key mappings:'
# for binding in custom_readline_bindings.get_readable_bindings():
# print >> sys.stderr, ' % 8s -> %s' % binding
import types
__BINDINGS = {
# Each dictionary key is a key-sequence.
# The corresponding dictionary value is the target binding.
# If the value is a pair, the zeroth element is the target binding;
# the first element is a human-readable alias for the binding.
# Use Tab to trigger shell-like autocomplete.
'tab': ('complete', 'tab-complete'),
# Use shift-Tab to insert a literal tab.
#
# "\e[Z" == "^[[Z" == shift-tab.
# To find out more exciting combinations like this, run "cat -v"
# and then press all your favourite non-ASCII keys.
r'"\e[Z"': 'tab-insert',
# Increase indentation of line using C-j (like C-t in Vim).
#
# Literally, this macro is: set-mark; beginning-of-line; insert-tab;
# exchange-point-and-mark; right-arrow (to compensate for the extra
# tab character inserted; Readline seems to track the set-mark position
# as a character-position offset).
r'"\C-x\C-m"': ('set-mark', 'set-mark (then C-xC-x to exchange-point-and-mark)'),
r'C-j': ('"\C-x\C-m\C-a\e[Z\C-x\C-x\e[C"', 'increase-indent'),
# Decrease indentation of line (the inverse of C-j).
#
# Literally, this macro is: left-arrow (since exchange-point-and-mark seems
# to become confused if the line is shorter than the set-mark position,
# which will occur if you were at the end of the line when you set the mark,
# and then you delete a character in the line); set-mark; beginning-of-line;
# right-arrow; backspace; exchange-point-and-mark.
#
# "\et" is the cryptic "keyseq" method of specifying Meta-t (Alt-t).
# It seems to be the only way to bind Meta/Alt on a modern Linux system.
# http://www.devheads.net/linux/fedora/user/readline-binding-still-frustrated-after-4-yrs-trying.htm
#
# Note that this binding also makes use of the binding of "\er" (Alt-r)
# to backward-delete-char that is performed later.
# Previously "\b" (the backspace character) was used, but for some reason
# it stopped working after the rebinding of Alt-r was added... :\
#r'"\et"': '"\e[D\C-x\C-m\C-a\e[C\b\C-x\C-x"',
#r'C-k': '"\e[D\C-x\C-m\C-a\e[C\b\C-x\C-x"',
r'C-k': ('"\e[D\C-x\C-m\C-a\e[C\er\C-x\C-x"', 'decrease-indent'),
# Bind the End key to menu-complete to cycle through possible completions,
# and the Home key to the reverse.
#r'"\eOF"': 'menu-complete',
#r'"\eOH"': 'menu-complete-backward',
r'C-t': ('menu-complete', 'tab-complete-cycle-forward'),
# Next, I wanted to use C-s for the reverse of C-t, but it seems
# that either the Python interpreter or Readline just eats it... :\
#r'C-s': 'menu-complete-backward',
r'"\et"': ('menu-complete-backward', 'tab-complete-cycle-reverse'),
# Bind Meta-c (Alt-c) to insert a comment at the beginning of the line.
r'"\ec"': 'insert-comment',
# Swap the move-by-char and move-by-word commands.
r'C-f': 'forward-word',
r'C-b': 'backward-word',
r'"\ef"': 'forward-char',
r'"\eb"': 'backward-char',
# Swap the delete-char and delete-word commands.
r'C-r': ('backward-kill-word', 'rubout-word (backward)'),
r'C-d': ('kill-word', 'delete-word (forward)'),
r'"\er"': ('backward-delete-char', 'rubout-char (backward)'),
r'"\ed"': ('delete-char', 'delete-char (forward)'),
# Remap C-r and C-s character-search commands to C-a and C-e
r'"\ea"': ('character-search-backward', 'char-search-backward (towards beginning of line)'),
r'"\ee"': ('character-search', 'char-search-forward (towards end of line)'),
r'C-h': 'previous-history',
r'C-n': 'next-history', # Already the default
r'"\eh"': 'reverse-search-history',
r'"\en"': 'forward-search-history',
}
def get_bindings():
def __get_binding(b):
if type(b) == types.TupleType:
return b[0]
else:
return b
return dict((k, __get_binding(b)) for k, b in __BINDINGS.iteritems())
def get_readable_bindings():
def __get_readable_keyseq(k):
k = k.replace('"', '')
if k == 'tab':
return 'Tab'
if k == '\\e[Z':
return 'S-Tab'
k = k.replace('\\C', 'C')
k = k.replace('\\e', 'M-')
return k
def __get_readable_binding(b):
if type(b) == types.TupleType:
return b[1]
else:
return b
bindings = [(__get_readable_keyseq(k), __get_readable_binding(b))
for k, b in __BINDINGS.iteritems()]
return sorted(bindings)