Changeset 553
- Timestamp:
- 06/15/08 05:17:19 (6 months ago)
- Files:
-
- cly/trunk/cly/interactive.py (modified) (11 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
cly/trunk/cly/interactive.py
r552 r553 19 19 20 20 import os 21 import readline22 21 import sys 23 22 import types … … 27 26 from cly.parser import Parser 28 27 28 try: 29 import readline 30 except ImportError: 31 readline = None 29 32 try: 30 33 from cly import _rlext … … 42 45 43 46 class InputDriver(object): 47 """Abstraction for line input.""" 48 44 49 def __init__(self, parser, prompt, history_file, history_length): 45 50 self.parser = parser 46 self. _prompt = prompt51 self.prompt = prompt 47 52 self.history_file = history_file 48 53 self.history_length = history_length 49 54 self._cli_inject_text = '' 50 55 self._completion_candidates = [] 56 57 def input(self): 58 """Input one line from user and return it.""" 59 raise NotImplementedError 60 61 def shutdown(self): 62 """Shutdown input driver.""" 63 64 @staticmethod 65 def choose(): 66 """Called to determine whether this driver is usable.""" 67 raise NotImplementedError 68 69 70 class DummyInputDriver(InputDriver): 71 """The horror.""" 72 @staticmethod 73 def choose(): 74 print >> sys.stderr, \ 75 'WARNING: Most line editing features are unavailable.' 76 return True 77 78 def input(self): 79 return raw_input(self.prompt) 80 81 82 class BaseReadlineDriver(InputDriver): 83 """Base class for readline variants.""" 84 def __init__(self, *args, **kwargs): 85 super(BaseReadlineDriver, self).__init__(*args, **kwargs) 51 86 try: 52 87 readline.set_history_length(self.history_length) … … 60 95 readline.set_startup_hook(self._redraw_input) 61 96 62 if _rlext: 63 self._bind_help = self._rlext_bind_help 64 self._force_redisplay = _rlext.force_redisplay 65 self._cursor = _rlext.cursor 66 elif pyreadline: 67 self._bind_help = self._pyrl_bind_help 68 self._force_redisplay = self._pyrl_force_redisplay 69 self._cursor = self._pyrl_cursor 70 else: 97 self.rl_bind_help() 98 99 @staticmethod 100 def choose(): 101 if readline: 71 102 print >> sys.stderr, \ 72 'WARNING: neither cly._rlext nor pyreadline found, ' \ 73 'contextual help will\n not be available.' 74 self._bind_help = lambda: None 75 self._force_redisplay = lambda: None 76 self._cursor = lambda _=None: None 77 78 self._bind_help() 79 103 'WARNING: neither pyreadline nor CLY\'s built-in readline ' \ 104 'extensions found,\n contextual help are not ' \ 105 'available.' 106 return readline 80 107 81 108 def shutdown(self): … … 89 116 return raw_input(self.prompt) 90 117 91 def set_prompt(self, prompt): 92 self._prompt = prompt 93 94 prompt = property(lambda s: s._prompt, lambda s, p: s.set_prompt(p)) 118 def rl_bind_help(self): 119 pass 120 121 def rl_force_redisplay(self): 122 raise NotImplementedError 123 124 def rl_get_cursor(self): 125 raise NotImplementedError 126 127 def rl_set_cursor(self, cursor): 128 raise NotImplementedError 129 130 cursor = property(lambda s: s.rl_get_cursor(), lambda s, c: s.rl_set_cursor(c)) 95 131 96 132 # Internal methods … … 117 153 except Exception, e: 118 154 self._dump_traceback(e) 119 self. _force_redisplay()155 self.rl_force_redisplay() 120 156 raise 121 157 … … 126 162 def _show_help(self, key, count): 127 163 try: 128 command = readline.get_line_buffer()[:self. _cursor()]164 command = readline.get_line_buffer()[:self.cursor] 129 165 context = self.parser.parse(command) 130 166 if context.remaining.strip(): … … 133 169 text = '%s^ invalid token (candidates are %s)' % \ 134 170 (' ' * (context.cursor + len(self.prompt)), 135 ', '.join(candidates))171 ', '.join(candidates)) 136 172 console.cerror(text) 137 self. _force_redisplay()173 self.rl_force_redisplay() 138 174 return 139 175 help = context.help() 140 176 print 141 177 console.cprint('\n'.join(help.format())) 142 self. _force_redisplay()178 self.rl_force_redisplay() 143 179 return 0 144 180 except Exception, e: 145 181 self._dump_traceback(e) 146 self. _force_redisplay()182 self.rl_force_redisplay() 147 183 return 0 148 184 149 # cly._rlext specific methods 150 def _rlext_bind_help(self): 151 _rlext.bind_key(ord('?'), self._show_help) 152 153 # pyreadline specific methods 154 def _pyrl_bind_help(self): 185 186 class PyReadlineDriver(BaseReadlineDriver): 187 """The IPython pure-Python pyreadline implementation.""" 188 @staticmethod 189 def choose(): 190 return pyreadline 191 192 def rl_bind_help(self): 155 193 def _show_help_proxy(_, __): 156 194 self._show_help(None, None) … … 163 201 pyreadline.parse_and_bind('F1: cly-help') 164 202 165 def _pyrl_force_redisplay(self):203 def rl_force_redisplay(self): 166 204 pyreadline.rl._print_prompt() 167 205 168 def _pyrl_cursor(self, cursor=None): 169 if cursor is None: 170 return pyreadline.rl.l_buffer.point 171 else: 172 pyreadline.rl.l_buffer.point = cursor 173 return 0 206 def rl_get_cursor(self): 207 return pyreadline.rl.l_buffer.point 208 209 def rl_set_cursor(self, cursor): 210 pyreadline.rl.l_buffer.point = cursor 211 212 213 class ExtendedReadlineDriver(BaseReadlineDriver): 214 """Use CLY's built-in readline extensions.""" 215 216 @staticmethod 217 def choose(): 218 return _rlext 219 220 def rl_bind_help(self): 221 _rlext.bind_key(ord('?'), self._show_help) 222 223 def rl_force_redisplay(self): 224 _rlext.force_redisplay() 225 226 def rl_get_cursor(self): 227 return _rlext.cursor() 228 229 def rl_set_cursor(self, cursor): 230 _rlext.cursor(cursor) 174 231 175 232 … … 227 284 self.data = data 228 285 229 self.input_driver = InputDriver(286 self.input_driver = input_driver( 230 287 parser, prompt, history_file, history_length 231 288 ) … … 331 388 332 389 390 # Available input drivers 391 DRIVERS = [ExtendedReadlineDriver, PyReadlineDriver, BaseReadlineDriver, 392 DummyInputDriver] 393 394 395 def input_driver(*args, **kwargs): 396 """Select the "best" available input driver.""" 397 for driver in DRIVERS: 398 if driver.choose(): 399 return driver(*args, **kwargs) 400 raise Error('No choose input driver found') 401 402 333 403 def interact(grammar_or_parser, inhibit_exceptions=False, with_backtrace=False, 334 404 *args, **kwargs):
