Commit | Line | Data |
---|---|---|
86530b38 AT |
1 | package Psh::Builtins::Bind;\r |
2 | \r | |
3 | require Psh::Util;\r | |
4 | \r | |
5 | =pod\r | |
6 | \r | |
7 | =item * C<bind [-m keymap] [-lvd] [-q name]>\r | |
8 | \r | |
9 | =item * C<bind [-m keymap] -f filename>\r | |
10 | \r | |
11 | =item * C<bind [-m keymap] keyseq:function-name>\r | |
12 | \r | |
13 | \r | |
14 | \r | |
15 | Display current readline key and function bindings,\r | |
16 | or bind a key sequence to a readline function or\r | |
17 | macro. The binding syntax accepted is identical to\r | |
18 | that of .inputrc, but each binding must be passed\r | |
19 | as a separate argument; e.g., '"\C-x\C-r":\r | |
20 | re-read-init-file'. Options, if supplied, have the\r | |
21 | following meanings:\r | |
22 | \r | |
23 | =over 8\r | |
24 | \r | |
25 | =item -m keymap\r | |
26 | \r | |
27 | Use keymap as the keymap to be affected by\r | |
28 | the subsequent bindings. Acceptable keymap\r | |
29 | names are emacs, emacs-standard, emacs-meta,\r | |
30 | emacs-ctlx, vi, vi-move, vi-command, and vi-\r | |
31 | insert. vi is equivalent to vi-command;\r | |
32 | emacs is equivalent to emacs-standard.\r | |
33 | \r | |
34 | =item -l\r | |
35 | \r | |
36 | List the names of all readline functions\r | |
37 | \r | |
38 | =item -v\r | |
39 | \r | |
40 | List current function names and bindings\r | |
41 | \r | |
42 | =item -d\r | |
43 | \r | |
44 | Dump function names and bindings in such a\r | |
45 | way that they can be re-read\r | |
46 | \r | |
47 | =item -f filename\r | |
48 | \r | |
49 | Read key bindings from filename\r | |
50 | \r | |
51 | =item -q function\r | |
52 | \r | |
53 | Query about which keys invoke the named\r | |
54 | \r | |
55 | =back\r | |
56 | \r | |
57 | =cut\r | |
58 | \r | |
59 | #\r | |
60 | # > TODO: How can we print out the current bindings in an\r | |
61 | # > ReadLine-implementation-independent way? We should allow rebinding\r | |
62 | # > of keys if Readline interface allows it, etc.\r | |
63 | #\r | |
64 | # This implementation supports GNU fully. It also kind of supports Perl.\r | |
65 | # All others it will refuse to work with.\r | |
66 | #\r | |
67 | # > Info:\r | |
68 | # > Bind a key: GNU: bind_key Perl: bind\r | |
69 | #\r | |
70 | # I implemented GNU using parse_and_bind as it gives a result more\r | |
71 | # consistant with what bash does.\r | |
72 | #\r | |
73 | # > Other interesting stuff\r | |
74 | # > Perl: set(EditingMode) - vi or emacs keybindings\r | |
75 | #\r | |
76 | # I impelemented this as a "keymap". (I notice that internally this\r | |
77 | # is what the EditingMode's are refered to as anyway.)\r | |
78 | #\r | |
79 | # > Perl: set(TcshCompleteMode) - tcsh menu completion mode\r | |
80 | # > GNU: lots and lots...\r | |
81 | #\r | |
82 | \r | |
83 | sub bi_bind {\r | |
84 | my $status = 0;\r | |
85 | if (defined($Psh::term) and $Psh::term->can('add_defun')) {\r | |
86 | my $args = pop;\r | |
87 | while (my $command = shift(@$args)) {\r | |
88 | if ($command eq '-l') {\r | |
89 | for my $function (sort($Psh::term->get_all_function_names)) {\r | |
90 | Psh::Util::print_out("$function\n");\r | |
91 | }\r | |
92 | } elsif ($command eq '-m') { # Set keymap\r | |
93 | my $keymap_name = shift(@$args);\r | |
94 | my $map = $Psh::term->get_keymap_by_name($keymap_name);\r | |
95 | if (defined($map)) {\r | |
96 | $Psh::term->set_keymap($map);\r | |
97 | } else {\r | |
98 | Psh::Util::print_out(qq{bind: `$keymap_name': illegal keymap name\n});\r | |
99 | $status = 1;\r | |
100 | }\r | |
101 | } elsif ($command eq '-v') { # Show values\r | |
102 | for my $function (sort($Psh::term->get_all_function_names)) {\r | |
103 | Psh::Util::print_out("$function ");\r | |
104 | my(@keys) = $Psh::term->invoking_keyseqs($function);\r | |
105 | if (@keys) {\r | |
106 | Psh::Util::print_out(qq{can be found on "},join('", "',@keys),qq{".\n});\r | |
107 | } else {\r | |
108 | Psh::Util::print_out("is not bound to any keys\n");\r | |
109 | }\r | |
110 | }\r | |
111 | } elsif ($command eq '-d') { # Dump values\r | |
112 | for my $function (sort($Psh::term->get_all_function_names)) {\r | |
113 | my(@keys) = $Psh::term->invoking_keyseqs($function);\r | |
114 | if (@keys) {\r | |
115 | foreach (@keys) {\r | |
116 | Psh::Util::print_out(qq{"$_": $function\n});\r | |
117 | }\r | |
118 | } else {\r | |
119 | Psh::Util::print_out("# $function (not bound)\n");\r | |
120 | }\r | |
121 | }\r | |
122 | } elsif ($command eq '-f') { # Read file\r | |
123 | my $file = shift(@$args);\r | |
124 | $Psh::term->read_init_file($file);\r | |
125 | if ($!) {\r | |
126 | Psh::Util::print_out("bind: cannot read $file: $!\n");\r | |
127 | $status = 1;\r | |
128 | }\r | |
129 | } elsif ($command eq '-q') { # Query a single function\r | |
130 | my $function = shift(@$args);\r | |
131 | Psh::Util::print_out("$function ");\r | |
132 | my(@keys) = $Psh::term->invoking_keyseqs($function);\r | |
133 | if (@keys) {\r | |
134 | Psh::Util::print_out(qq{can be found on "},join('", "',@keys),qq{".\n});\r | |
135 | } else {\r | |
136 | Psh::Util::print_out("is not bound to any keys\n");\r | |
137 | }\r | |
138 | } elsif ($command =~ /:/) {\r | |
139 | unless ($command =~ /:./) {\r | |
140 | # This let's the user do things like this:\r | |
141 | # bind "\en": history-search-forward "\ep": history-search backward\r | |
142 | $command .= shift(@$args);\r | |
143 | }\r | |
144 | ### This is to make my bash-happy bind statements work.\r | |
145 | ### This is undoubtably dumb. If someone could tell me\r | |
146 | ### how to make readline work with M- as meta, I'd be\r | |
147 | ### enternally grateful.\r | |
148 | $command =~ s/^M-(.)/"\\e$1"/g;\r | |
149 | ###\r | |
150 | $Psh::term->parse_and_bind($command);\r | |
151 | } else {\r | |
152 | # print help (unknown option)\r | |
153 | Psh::Util::print_out("bind: illegal option: $command\n");\r | |
154 | Psh::Util::print_out("usage: bind [-lvd] [-m keymap] [-f filename] [-q name] [keyseq:readline_func]\n");\r | |
155 | $status = 1;\r | |
156 | last;\r | |
157 | }\r | |
158 | }\r | |
159 | } elsif (defined($Psh::term) and $Psh::term->can('bind')) {\r | |
160 | # Term::ReadLine::Perl\r | |
161 | my $args = pop;\r | |
162 | while (my $command = shift(@$args)) {\r | |
163 | if ($command eq '-l') {\r | |
164 | Psh::Util::print_out("bind: -l option currently not supported by ".ref($Psh::term)."\n");\r | |
165 | $status = 1;\r | |
166 | last;\r | |
167 | } elsif ($command eq '-m') { # Set keymap\r | |
168 | my $keymap_name = shift(@$args);\r | |
169 | my $map = ($keymap_name =~ /^(emacs|vi)$/i)?$1:undef;\r | |
170 | if (defined($map)) {\r | |
171 | $Psh::term->set('EditingMode',$map);\r | |
172 | } else {\r | |
173 | Psh::Util::print_out(qq{bind: `$keymap_name': illegal keymap name\n});\r | |
174 | $status = 1;\r | |
175 | }\r | |
176 | } elsif ($command eq '-v') { # Show values\r | |
177 | Psh::Util::print_out("bind: -v option currently not supported by ".ref($Psh::term)."\n");\r | |
178 | $status = 1;\r | |
179 | last;\r | |
180 | } elsif ($command eq '-d') { # Dump values\r | |
181 | Psh::Util::print_out("bind: -d option currently not supported by ".ref($Psh::term)."\n");\r | |
182 | $status = 1;\r | |
183 | last;\r | |
184 | } elsif ($command eq '-f') { # Read file\r | |
185 | Psh::Util::print_out("bind: -f option currently not supported by ".ref($Psh::term)."\n");\r | |
186 | $status = 1;\r | |
187 | last;\r | |
188 | } elsif ($command eq '-q') { # Query a single function\r | |
189 | Psh::Util::print_out("bind: -q option currently not supported by ".ref($Psh::term)."\n");\r | |
190 | $status = 1;\r | |
191 | last;\r | |
192 | } elsif ($command =~ /:/) {\r | |
193 | unless ($command =~ /:./) {\r | |
194 | # This let's the user do things like this:\r | |
195 | # bind "\en": history-search-forward "\ep": history-search backward\r | |
196 | $command .= shift(@$args);\r | |
197 | }\r | |
198 | my($keys,$function) = split(/\s*:\s*/,$command,2);\r | |
199 | $keys =~ s/^"(.*)"$/$1/ or\r | |
200 | $keys =~ s/^'(.*)'$/$1/;\r | |
201 | $Psh::term->bind($keys,$function);\r | |
202 | } else {\r | |
203 | # print help (unknown option)\r | |
204 | Psh::Util::print_out("bind: illegal option: $command\n");\r | |
205 | Psh::Util::print_out("usage: bind [-lvd] [-m keymap] [-f filename] [-q name] [keyseq:readline_func]\n");\r | |
206 | $status = 1;\r | |
207 | last;\r | |
208 | }\r | |
209 | }\r | |
210 | } elsif (defined($Psh::term) and ref($Psh::term)) {\r | |
211 | Psh::Util::print_out("bind requires a more capable readline than ".ref($Psh::term)."\n");\r | |
212 | $status = 1;\r | |
213 | } else {\r | |
214 | Psh::Util::print_out("bind: No effect in non-interactive terminal\n");\r | |
215 | $status = 1;\r | |
216 | }\r | |
217 | return ($status,undef);\r | |
218 | }\r | |
219 | \r | |
220 | 1;\r |