1   
2   
3   
4   
5   
6   
7   
8   
9   package jline.console;
10  
11  import java.util.HashMap;
12  import java.util.Map;
13  
14  
15  
16  
17  
18  
19  
20  public class KeyMap {
21      
22      public static final String VI_MOVE        = "vi-move";
23      public static final String VI_INSERT      = "vi-insert";
24      public static final String EMACS          = "emacs";
25      public static final String EMACS_STANDARD = "emacs-standard";
26      public static final String EMACS_CTLX     = "emacs-ctlx";
27      public static final String EMACS_META     = "emacs-meta";
28  
29      private static final int KEYMAP_LENGTH = 256;
30  
31      private static final Object NULL_FUNCTION = new Object();
32  
33      private Object[] mapping = new Object[KEYMAP_LENGTH];
34      private Object anotherKey = null;
35      private String name;
36      private boolean isViKeyMap;
37      
38      public KeyMap(String name, boolean isViKeyMap) {
39          this(name, new Object[KEYMAP_LENGTH], isViKeyMap);
40      }
41  
42      protected KeyMap(String name, Object[] mapping, boolean isViKeyMap) {
43          this.mapping = mapping;
44          this.name = name;
45          this.isViKeyMap = isViKeyMap;
46      }
47      
48      public boolean isViKeyMap() {
49          return isViKeyMap;
50      }
51      
52      public String getName() {
53          return name;
54      }
55  
56      public Object getAnotherKey() {
57          return anotherKey;
58      }
59  
60      public void from(KeyMap other) {
61          this.mapping = other.mapping;
62          this.anotherKey = other.anotherKey;
63      }
64  
65      public Object getBound( CharSequence keySeq ) {
66          if (keySeq != null && keySeq.length() > 0) {
67              KeyMap map = this;
68              for (int i = 0; i < keySeq.length(); i++) {
69                  char c = keySeq.charAt(i);
70                  if (c > 255) {
71                      return Operation.SELF_INSERT;
72                  }
73                  if (map.mapping[c] instanceof KeyMap) {
74                      if (i == keySeq.length() - 1) {
75                          return map.mapping[c];
76                      } else {
77                          map = (KeyMap) map.mapping[c];
78                      }
79                  } else {
80                      return map.mapping[c];
81                  }
82              }
83          }
84          return null;
85      }
86  
87      public void bindIfNotBound( CharSequence keySeq, Object function ) {
88          
89          bind (this, keySeq, function, true);
90      }
91      
92      public void bind( CharSequence keySeq, Object function ) {
93          
94          bind (this, keySeq, function, false);
95      }
96      
97      private static void bind( KeyMap map, CharSequence keySeq, Object function ) {
98          
99          bind (map, keySeq, function, false);
100     }
101     
102     private static void bind( KeyMap map, CharSequence keySeq, Object function, 
103             boolean onlyIfNotBound ) {
104 
105         if (keySeq != null && keySeq.length() > 0) {
106             for (int i = 0; i < keySeq.length(); i++) {
107                 char c = keySeq.charAt(i);
108                 if (c >= map.mapping.length) {
109                     return;
110                 }
111                 if (i < keySeq.length() - 1) {
112                     if (!(map.mapping[c] instanceof KeyMap)) {
113                         KeyMap m = new KeyMap("anonymous", false);
114                         if (map.mapping[c] != Operation.DO_LOWERCASE_VERSION) {
115                             m.anotherKey = map.mapping[c];
116                         }
117                         map.mapping[c] = m;
118                     }
119                     map = (KeyMap) map.mapping[c];
120                 } else {
121                     if (function == null) {
122                         function = NULL_FUNCTION;
123                     }
124                     if (map.mapping[c] instanceof KeyMap) {
125                         map.anotherKey = function;
126                     } else {
127                         Object op = map.mapping[c];
128                         if (onlyIfNotBound == false 
129                             || op == null 
130                             || op == Operation.DO_LOWERCASE_VERSION 
131                             || op == Operation.VI_MOVEMENT_MODE ) {
132                             
133                         }
134                         
135                         map.mapping[c] = function;
136                     }
137                 }
138             }
139         }
140     }
141 
142     public void setBlinkMatchingParen(boolean on) {
143         if (on) {
144             bind( "}", Operation.INSERT_CLOSE_CURLY );
145             bind( ")", Operation.INSERT_CLOSE_PAREN );
146             bind( "]", Operation.INSERT_CLOSE_SQUARE );
147         }
148     }
149 
150     private static void bindArrowKeys(KeyMap map) {
151         
152         
153         bind( map, "\033[0A", Operation.PREVIOUS_HISTORY );
154         bind( map, "\033[0B", Operation.BACKWARD_CHAR );
155         bind( map, "\033[0C", Operation.FORWARD_CHAR );
156         bind( map, "\033[0D", Operation.NEXT_HISTORY );
157 
158         
159         bind( map, "\340\000", Operation.KILL_WHOLE_LINE );
160         bind( map, "\340\107", Operation.BEGINNING_OF_LINE );
161         bind( map, "\340\110", Operation.PREVIOUS_HISTORY );
162         bind( map, "\340\111", Operation.BEGINNING_OF_HISTORY );
163         bind( map, "\340\113", Operation.BACKWARD_CHAR );
164         bind( map, "\340\115", Operation.FORWARD_CHAR );
165         bind( map, "\340\117", Operation.END_OF_LINE );
166         bind( map, "\340\120", Operation.NEXT_HISTORY );
167         bind( map, "\340\121", Operation.END_OF_HISTORY );
168         bind( map, "\340\122", Operation.OVERWRITE_MODE );
169         bind( map, "\340\123", Operation.DELETE_CHAR );
170 
171         bind( map, "\000\107", Operation.BEGINNING_OF_LINE );
172         bind( map, "\000\110", Operation.PREVIOUS_HISTORY );
173         bind( map, "\000\111", Operation.BEGINNING_OF_HISTORY );
174         bind( map, "\000\110", Operation.PREVIOUS_HISTORY );
175         bind( map, "\000\113", Operation.BACKWARD_CHAR );
176         bind( map, "\000\115", Operation.FORWARD_CHAR );
177         bind( map, "\000\117", Operation.END_OF_LINE );
178         bind( map, "\000\120", Operation.NEXT_HISTORY );
179         bind( map, "\000\121", Operation.END_OF_HISTORY );
180         bind( map, "\000\122", Operation.OVERWRITE_MODE );
181         bind( map, "\000\123", Operation.DELETE_CHAR );
182 
183         bind( map, "\033[A", Operation.PREVIOUS_HISTORY );
184         bind( map, "\033[B", Operation.NEXT_HISTORY );
185         bind( map, "\033[C", Operation.FORWARD_CHAR );
186         bind( map, "\033[D", Operation.BACKWARD_CHAR );
187         bind( map, "\033[H", Operation.BEGINNING_OF_LINE );
188         bind( map, "\033[F", Operation.END_OF_LINE );
189 
190         bind( map, "\033OA", Operation.PREVIOUS_HISTORY );
191         bind( map, "\033OB", Operation.NEXT_HISTORY );
192         bind( map, "\033OC", Operation.FORWARD_CHAR );
193         bind( map, "\033OD", Operation.BACKWARD_CHAR );
194         bind( map, "\033OH", Operation.BEGINNING_OF_LINE );
195         bind( map, "\033OF", Operation.END_OF_LINE );
196 
197         bind( map, "\033[1~", Operation.BEGINNING_OF_LINE);
198         bind( map, "\033[4~", Operation.END_OF_LINE);
199         bind( map, "\033[3~", Operation.DELETE_CHAR);
200 
201         
202         bind( map, "\0340H", Operation.PREVIOUS_HISTORY );
203         bind( map, "\0340P", Operation.NEXT_HISTORY );
204         bind( map, "\0340M", Operation.FORWARD_CHAR );
205         bind( map, "\0340K", Operation.BACKWARD_CHAR );
206     }
207 
208 
209 
210 
211 
212 
213 
214 
215 
216     public static boolean isMeta( char c ) {
217         return c > 0x7f && c <= 0xff;
218     }
219 
220     public static char unMeta( char c ) {
221         return (char) (c & 0x7F);
222     }
223 
224     public static char meta( char c ) {
225         return (char) (c | 0x80);
226     }
227     
228     public static Map<String, KeyMap> keyMaps() {
229         Map<String, KeyMap> keyMaps = new HashMap<String, KeyMap>();
230         
231         KeyMap emacs = emacs();
232         bindArrowKeys(emacs);
233         keyMaps.put(EMACS, emacs);
234         keyMaps.put(EMACS_STANDARD, emacs);
235         keyMaps.put(EMACS_CTLX, (KeyMap) emacs.getBound("\u0018"));
236         keyMaps.put(EMACS_META, (KeyMap) emacs.getBound("\u001b"));
237         
238         KeyMap viMov = viMovement();
239         bindArrowKeys(viMov);
240         keyMaps.put(VI_MOVE, viMov);
241         keyMaps.put("vi-command", viMov);
242         
243         KeyMap viIns = viInsertion();
244         bindArrowKeys(viIns);
245         keyMaps.put(VI_INSERT, viIns);
246         keyMaps.put("vi", viIns);
247         
248         return keyMaps;
249     }
250 
251     public static KeyMap emacs() {
252         Object[] map = new Object[KEYMAP_LENGTH];
253         Object[] ctrl = new Object[] {
254                         
255                         Operation.SET_MARK,                 
256                         Operation.BEGINNING_OF_LINE,        
257                         Operation.BACKWARD_CHAR,            
258                         Operation.INTERRUPT,                
259                         Operation.EXIT_OR_DELETE_CHAR,      
260                         Operation.END_OF_LINE,              
261                         Operation.FORWARD_CHAR,             
262                         Operation.ABORT,                    
263                         Operation.BACKWARD_DELETE_CHAR,     
264                         Operation.COMPLETE,                 
265                         Operation.ACCEPT_LINE,              
266                         Operation.KILL_LINE,                
267                         Operation.CLEAR_SCREEN,             
268                         Operation.ACCEPT_LINE,              
269                         Operation.NEXT_HISTORY,             
270                         null,                               
271                         Operation.PREVIOUS_HISTORY,         
272                         Operation.QUOTED_INSERT,            
273                         Operation.REVERSE_SEARCH_HISTORY,   
274                         Operation.FORWARD_SEARCH_HISTORY,   
275                         Operation.TRANSPOSE_CHARS,          
276                         Operation.UNIX_LINE_DISCARD,        
277                         Operation.QUOTED_INSERT,            
278                         Operation.UNIX_WORD_RUBOUT,         
279                         emacsCtrlX(),                       
280                         Operation.YANK,                     
281                         null,                               
282                         emacsMeta(),                        
283                         null,                               
284                         Operation.CHARACTER_SEARCH,         
285                         null,                               
286                         Operation.UNDO,                     
287                 };
288         System.arraycopy( ctrl, 0, map, 0, ctrl.length );
289         for (int i = 32; i < 256; i++) {
290             map[i] = Operation.SELF_INSERT;
291         }
292         map[DELETE] = Operation.BACKWARD_DELETE_CHAR;
293         return new KeyMap(EMACS, map, false);
294     }
295 
296     public static final char CTRL_D = (char) 4;
297     public static final char CTRL_G = (char) 7;
298     public static final char CTRL_H = (char) 8;
299     public static final char CTRL_I = (char) 9;
300     public static final char CTRL_J = (char) 10;
301     public static final char CTRL_M = (char) 13;
302     public static final char CTRL_R = (char) 18;
303     public static final char CTRL_S = (char) 19;
304     public static final char CTRL_U = (char) 21;
305     public static final char CTRL_X = (char) 24;
306     public static final char CTRL_Y = (char) 25;
307     public static final char ESCAPE = (char) 27; 
308     public static final char CTRL_OB = (char) 27; 
309     public static final char CTRL_CB = (char) 29; 
310 
311     public static final int DELETE = (char) 127;
312 
313     public static KeyMap emacsCtrlX() {
314         Object[] map = new Object[KEYMAP_LENGTH];
315         map[CTRL_G] = Operation.ABORT;
316         map[CTRL_R] = Operation.RE_READ_INIT_FILE;
317         map[CTRL_U] = Operation.UNDO;
318         map[CTRL_X] = Operation.EXCHANGE_POINT_AND_MARK;
319         map['('] = Operation.START_KBD_MACRO;
320         map[')'] = Operation.END_KBD_MACRO;
321         for (int i = 'A'; i <= 'Z'; i++) {
322             map[i] = Operation.DO_LOWERCASE_VERSION;
323         }
324         map['e'] = Operation.CALL_LAST_KBD_MACRO;
325         map[DELETE] = Operation.KILL_LINE;
326         return new KeyMap(EMACS_CTLX, map, false);
327     }
328 
329     public static KeyMap emacsMeta() {
330         Object[] map = new Object[KEYMAP_LENGTH];
331         map[CTRL_G] = Operation.ABORT;
332         map[CTRL_H] = Operation.BACKWARD_KILL_WORD;
333         map[CTRL_I] = Operation.TAB_INSERT;
334         map[CTRL_J] = Operation.VI_EDITING_MODE;
335         map[CTRL_M] = Operation.VI_EDITING_MODE;
336         map[CTRL_R] = Operation.REVERT_LINE;
337         map[CTRL_Y] = Operation.YANK_NTH_ARG;
338         map[CTRL_OB] = Operation.COMPLETE;
339         map[CTRL_CB] = Operation.CHARACTER_SEARCH_BACKWARD;
340         map[' '] = Operation.SET_MARK;
341         map['#'] = Operation.INSERT_COMMENT;
342         map['&'] = Operation.TILDE_EXPAND;
343         map['*'] = Operation.INSERT_COMPLETIONS;
344         map['-'] = Operation.DIGIT_ARGUMENT;
345         map['.'] = Operation.YANK_LAST_ARG;
346         map['<'] = Operation.BEGINNING_OF_HISTORY;
347         map['='] = Operation.POSSIBLE_COMPLETIONS;
348         map['>'] = Operation.END_OF_HISTORY;
349         map['?'] = Operation.POSSIBLE_COMPLETIONS;
350         for (int i = 'A'; i <= 'Z'; i++) {
351             map[i] = Operation.DO_LOWERCASE_VERSION;
352         }
353         map['\\'] = Operation.DELETE_HORIZONTAL_SPACE;
354         map['_'] = Operation.YANK_LAST_ARG;
355         map['b'] = Operation.BACKWARD_WORD;
356         map['c'] = Operation.CAPITALIZE_WORD;
357         map['d'] = Operation.KILL_WORD;
358         map['f'] = Operation.FORWARD_WORD;
359         map['l'] = Operation.DOWNCASE_WORD;
360         map['p'] = Operation.NON_INCREMENTAL_REVERSE_SEARCH_HISTORY;
361         map['r'] = Operation.REVERT_LINE;
362         map['t'] = Operation.TRANSPOSE_WORDS;
363         map['u'] = Operation.UPCASE_WORD;
364         map['y'] = Operation.YANK_POP;
365         map['~'] = Operation.TILDE_EXPAND;
366         map[DELETE] = Operation.BACKWARD_KILL_WORD;
367         return new KeyMap(EMACS_META, map, false);
368     }
369 
370     public static KeyMap viInsertion() {
371         Object[] map = new Object[KEYMAP_LENGTH];
372         Object[] ctrl = new Object[] {
373                         
374                         null,                               
375                         Operation.SELF_INSERT,              
376                         Operation.SELF_INSERT,              
377                         Operation.SELF_INSERT,              
378                         Operation.VI_EOF_MAYBE,             
379                         Operation.SELF_INSERT,              
380                         Operation.SELF_INSERT,              
381                         Operation.SELF_INSERT,              
382                         Operation.BACKWARD_DELETE_CHAR,     
383                         Operation.COMPLETE,                 
384                         Operation.ACCEPT_LINE,              
385                         Operation.SELF_INSERT,              
386                         Operation.SELF_INSERT,              
387                         Operation.ACCEPT_LINE,              
388                         Operation.MENU_COMPLETE,            
389                         Operation.SELF_INSERT,              
390                         Operation.MENU_COMPLETE_BACKWARD,   
391                         Operation.SELF_INSERT,              
392                         Operation.REVERSE_SEARCH_HISTORY,   
393                         Operation.FORWARD_SEARCH_HISTORY,   
394                         Operation.TRANSPOSE_CHARS,          
395                         Operation.UNIX_LINE_DISCARD,        
396                         Operation.QUOTED_INSERT,            
397                         Operation.UNIX_WORD_RUBOUT,         
398                         Operation.SELF_INSERT,              
399                         Operation.YANK,                     
400                         Operation.SELF_INSERT,              
401                         Operation.VI_MOVEMENT_MODE,         
402                         Operation.SELF_INSERT,              
403                         Operation.SELF_INSERT,              
404                         Operation.SELF_INSERT,              
405                         Operation.UNDO,                     
406                 };
407         System.arraycopy( ctrl, 0, map, 0, ctrl.length );
408         for (int i = 32; i < 256; i++) {
409             map[i] = Operation.SELF_INSERT;
410         }
411         map[DELETE] = Operation.BACKWARD_DELETE_CHAR;
412         return new KeyMap(VI_INSERT, map, false);
413     }
414 
415     public static KeyMap viMovement() {
416         Object[] map = new Object[KEYMAP_LENGTH];
417         Object[] low = new Object[] {
418                         
419                         null,                               
420                         null,                               
421                         null,                               
422                         Operation.INTERRUPT,                
423                         
424 
425 
426 
427                         Operation.VI_EOF_MAYBE,             
428                         Operation.EMACS_EDITING_MODE,       
429                         null,                               
430                         Operation.ABORT,                    
431                         Operation.BACKWARD_CHAR,            
432                         null,                               
433                         Operation.VI_MOVE_ACCEPT_LINE,      
434                         Operation.KILL_LINE,                
435                         Operation.CLEAR_SCREEN,             
436                         Operation.VI_MOVE_ACCEPT_LINE,      
437                         Operation.VI_NEXT_HISTORY,          
438                         null,                               
439                         Operation.VI_PREVIOUS_HISTORY,      
440                         
441 
442 
443 
444                         Operation.QUOTED_INSERT,            
445                         
446                         
447 
448 
449 
450 
451                         Operation.REVERSE_SEARCH_HISTORY,   
452                         
453                         Operation.FORWARD_SEARCH_HISTORY,   
454                         Operation.TRANSPOSE_CHARS,          
455                         Operation.UNIX_LINE_DISCARD,        
456                         
457                         Operation.QUOTED_INSERT,            
458                         Operation.UNIX_WORD_RUBOUT,         
459                         null,                               
460                         
461                         Operation.YANK,                     
462                         null,                               
463                         emacsMeta(),                        
464                         null,                               
465                         
466                         Operation.CHARACTER_SEARCH,         
467                         null,                               
468                         
469                         Operation.UNDO,                     
470                         Operation.FORWARD_CHAR,             
471                         null,                               
472                         null,                               
473                         Operation.VI_INSERT_COMMENT,        
474                         Operation.END_OF_LINE,              
475                         Operation.VI_MATCH,                 
476                         Operation.VI_TILDE_EXPAND,          
477                         null,                               
478                         null,                               
479                         null,                               
480                         
481                         Operation.VI_COMPLETE,              
482                         Operation.VI_NEXT_HISTORY,          
483                         Operation.VI_CHAR_SEARCH,           
484                         Operation.VI_PREVIOUS_HISTORY,      
485                         
486                         Operation.VI_REDO,                  
487                         Operation.VI_SEARCH,                
488                         Operation.VI_BEGNNING_OF_LINE_OR_ARG_DIGIT, 
489                         Operation.VI_ARG_DIGIT,             
490                         Operation.VI_ARG_DIGIT,             
491                         Operation.VI_ARG_DIGIT,             
492                         Operation.VI_ARG_DIGIT,             
493                         Operation.VI_ARG_DIGIT,             
494                         Operation.VI_ARG_DIGIT,             
495                         Operation.VI_ARG_DIGIT,             
496                         Operation.VI_ARG_DIGIT,             
497                         Operation.VI_ARG_DIGIT,             
498                         null,                               
499                         Operation.VI_CHAR_SEARCH,           
500                         null,                               
501                         Operation.VI_COMPLETE,              
502                         null,                               
503                         Operation.VI_SEARCH,                
504                         null,                               
505                         Operation.VI_APPEND_EOL,            
506                         Operation.VI_PREV_WORD,             
507                         Operation.VI_CHANGE_TO_EOL,         
508                         Operation.VI_DELETE_TO_EOL,         
509                         Operation.VI_END_WORD,              
510                         Operation.VI_CHAR_SEARCH,           
511                         
512                         Operation.VI_FETCH_HISTORY,         
513                         null,                               
514                         Operation.VI_INSERT_BEG,            
515                         null,                               
516                         null,                               
517                         null,                               
518                         null,                               
519                         Operation.VI_SEARCH_AGAIN,          
520                         null,                               
521                         Operation.VI_PUT,                   
522                         null,                               
523                         
524                         Operation.VI_REPLACE,               
525                         Operation.VI_KILL_WHOLE_LINE,       
526                         Operation.VI_CHAR_SEARCH,           
527                         
528                         Operation.REVERT_LINE,              
529                         null,                               
530                         Operation.VI_NEXT_WORD,             
531                         Operation.VI_RUBOUT,                
532                         Operation.VI_YANK_TO,               
533                         null,                               
534                         null,                               
535                         Operation.VI_COMPLETE,              
536                         null,                               
537                         Operation.VI_FIRST_PRINT,           
538                         Operation.VI_YANK_ARG,              
539                         Operation.VI_GOTO_MARK,             
540                         Operation.VI_APPEND_MODE,           
541                         Operation.VI_PREV_WORD,             
542                         Operation.VI_CHANGE_TO,             
543                         Operation.VI_DELETE_TO,             
544                         Operation.VI_END_WORD,              
545                         Operation.VI_CHAR_SEARCH,           
546                         null,                               
547                         Operation.BACKWARD_CHAR,            
548                         Operation.VI_INSERTION_MODE,        
549                         Operation.NEXT_HISTORY,             
550                         Operation.PREVIOUS_HISTORY,         
551                         Operation.FORWARD_CHAR,             
552                         Operation.VI_SET_MARK,              
553                         Operation.VI_SEARCH_AGAIN,          
554                         null,                               
555                         Operation.VI_PUT,                   
556                         null,                               
557                         Operation.VI_CHANGE_CHAR,           
558                         Operation.VI_SUBST,                 
559                         Operation.VI_CHAR_SEARCH,           
560                         Operation.UNDO,                     
561                         null,                               
562                         Operation.VI_NEXT_WORD,             
563                         Operation.VI_DELETE,                
564                         Operation.VI_YANK_TO,               
565                         null,                               
566                         null,                               
567                         Operation.VI_COLUMN,                
568                         null,                               
569                         Operation.VI_CHANGE_CASE,           
570                         Operation.VI_DELETE                 
571                 };
572         System.arraycopy( low, 0, map, 0, low.length );
573         for (int i = 128; i < 256; i++) {
574             map[i] = null;
575         }
576         return new KeyMap(VI_MOVE, map, false);
577     }
578 }