Changeset 425
- Timestamp:
- 05/18/07 11:47:29 (2 years ago)
- Files:
-
- cly/trunk/cly/console.py (modified) (2 diffs)
- cly/trunk/cly/__init__.py (modified) (6 diffs)
- cly/trunk/cly/interactive.py (modified) (4 diffs)
- cly/trunk/cly/types.py (moved) (moved from cly/trunk/cly/variables.py)
- cly/trunk/doc/tutorial.py (modified) (1 diff)
- cly/trunk/doc/video1.py (added)
- cly/trunk/.todo (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
cly/trunk/cly/console.py
r423 r425 45 45 46 46 47 _decode_re = re.compile(r''' [^^]+|\^([N0-7BU])''')47 _decode_re = re.compile(r'''\^([N0-7BU])|.''') 48 48 _encode_re = re.compile(r'''\033(?:[^[]|$)|\033\[(.*?)m''') 49 49 _cprint_strip = re.compile(r'''\^([N0-7BU])''') 50 _cwrap_re = re.compile(r'''(\n)|(\s+)|((?:\^[N0-7BU]|\S)+\b[^\n^\w]*) ''')50 _cwrap_re = re.compile(r'''(\n)|(\s+)|((?:\^[N0-7BU]|\S)+\b[^\n^\w]*)|(.)''') 51 51 _colour_terminal = 0 52 52 … … 240 240 241 241 def error(*args): 242 """Print a red error message prefixed by ERR."""243 cprint(sys.stderr, "^1^B ERR" + ' '.join(map(str, args)) + '^N')242 """Print a message in red to stderr.""" 243 cprint(sys.stderr, "^1^B" + ' '.join(map(str, args)) + '^N') 244 244 245 245 246 246 def fatal(*args): 247 """Print a red error message prefixed by FTL, then exit with status -1"""248 cprint(sys.stderr, "^1^B FTL" + ' '.join(map(str, args)) + '^N')247 """Print a message in red to stderr then exit with status -1.""" 248 cprint(sys.stderr, "^1^B" + ' '.join(map(str, args)) + '^N') 249 249 sys.exit(-1) 250 250 251 251 252 252 def warning(*args): 253 """Print a yellow warning message prefixed by WRN"""254 cprint(sys.stderr, "^3^B WRN" + ' '.join(map(str, args)) + '^N')253 """Print a yellow warning message to stderr.""" 254 cprint(sys.stderr, "^3^B" + ' '.join(map(str, args)) + '^N') 255 255 256 256 257 257 def info(*args): 258 """Print a green notice prefixed by INF."""259 cprint("^2 ^BINF ^B" + ' '.join(map(str, args)) + '^N')258 """Print a green notice.""" 259 cprint("^2" + ' '.join(map(str, args)) + '^N') 260 260 261 261 cly/trunk/cly/__init__.py
r418 r425 247 247 """Iterate over child nodes, ignoring context. 248 248 249 >>> for child in Grammar(one=Node('One'), two=Node('Two')): print child 250 <Node:/one> 249 >>> tree = Node('One')(two=Node('Two'), three=Node('Three')) 250 >>> for child in tree: print child 251 <Node:/three> 251 252 <Node:/two> 252 253 """ … … 256 257 yield child 257 258 259 def __setitem__(self, key, child): 260 """Emulate dictionary set. 261 262 >>> node = Node('One') 263 >>> node['two'] = Node('Two') 264 >>> for i in node.walk(): print i 265 <Node:/> 266 <Node:/two> 267 """ 268 self(**{key: child}) 269 270 def __getitem__(self, key): 271 """Emulate dictionary get. 272 273 >>> node = Node('One')(two=Node('Two')) 274 >>> node['two'] 275 <Node:/two> 276 """ 277 return self._children[key] 278 279 def __delitem__(self, key): 280 """Emulate dictionary delete. 281 282 >>> node = Node('One')(two=Node('Two'), three=Node('Three')) 283 >>> for i in node.walk(): print i 284 <Node:/> 285 <Node:/three> 286 <Node:/two> 287 >>> del node['two'] 288 >>> for i in node.walk(): print i 289 <Node:/> 290 <Node:/three> 291 """ 292 child = self._children.pop(key) 293 child.parent = None 294 295 def __contains__(self, key): 296 """Emulate dictionary key existence test. 297 298 >>> node = Node('One')(two=Node('Two'), three=Node('Three')) 299 >>> 'two' in node 300 True 301 """ 302 return key in self._children 303 258 304 def walk(self): 259 305 """Perform a recursive walk of the grammar tree. 260 306 261 >>> parser = Parser(Grammar(one=Node('One'), two=Node('Two', three=Node('Three')))) 262 >>> for node in parser: print node 263 <Grammar:/> 307 >>> tree = Node('One')(two=Node('Two', three=Node('Three'), 308 ... four=Node('Four'))) 309 >>> for i in tree.walk(): print i 310 <Node:/> 264 311 <Node:/two> 312 <Node:/two/four> 265 313 <Node:/two/three> 266 <Node:/one>267 314 """ 268 315 def walk(root): … … 468 515 return alias.valid(context) 469 516 517 def visible(self, context): 518 alias = self.parser.find(self.alias) 519 return alias.visible(context) 520 470 521 def selected(self, context, match): 471 522 """This node was selected by the parser.""" … … 523 574 524 575 def help(self, context): 525 if not self.visible :576 if not self.visible(context): 526 577 return 527 578 if isinstance(self.doc, basestring): … … 698 749 699 750 for child in node.children(context, follow=True): 700 add_help(child) 751 if child.visible(context): 752 add_help(child) 701 753 702 754 self.help.sort() … … 762 814 remaining = property(_get_remaining_input) 763 815 816 def _get_parsed(self): 817 """Return command text that has been successfully parsed.""" 818 return self.command[:self.cursor] 819 parsed = property(_get_parsed) 820 764 821 def _last_node(self): 765 822 """Return the last node parsed.""" cly/trunk/cly/interactive.py
r423 r425 23 23 import cly 24 24 import cly.rlext 25 from cly.console import error as print_error 25 import cly.console as console 26 26 27 27 … … 78 78 Interact.history_length = history_length 79 79 Interact.completion_delimiters = completion_delimiters 80 Interact.completion_key = completion_key 80 81 81 82 try: … … 115 116 context.execute() 116 117 except cly.ParseError, e: 117 print_error(e)118 self.print_error(context, e) 118 119 return context 119 120 121 def print_error(self, context, e): 122 """Called by `interact_once()` to print a ParseError.""" 123 candidates = [help[1] for help in context.help()] 124 if len(candidates) > 1: 125 message = '%s (candidates are %s)' 126 else: 127 message = '%s (expected %s)' 128 message = message % (str(e), ', '.join(candidates)) 129 self.error_at_cursor(context, message) 130 131 def error_at_cursor(self, context, text): 132 """Attempt to intelligently print an error at the current cursor 133 offset.""" 134 text = str(text) 135 term_width = console.termwidth() 136 indent = ' ' * (context.cursor % term_width 137 + len(Interact.prompt)) 138 if len(indent + text) > term_width: 139 console.error(indent + '^') 140 console.error(text) 141 else: 142 console.error(indent + '^ ' + text) 120 143 121 144 def interact_loop(self): … … 180 203 (' ' * (context.cursor + len(Interact.prompt)), 181 204 ', '.join(candidates)) 182 print_error(text)205 console.error(text) 183 206 cly.rlext.force_redisplay() 184 207 return cly/trunk/doc/tutorial.py
r423 r425 13 13 14 14 grammar = Grammar( 15 quit=Node('Quit')( 15 # Quit is distinct from normal commands, so lets reflect that with a visual 16 # cue. 17 # Those are just a few of the features of CLY. Check the tutorial for more 18 # and the API documentation for detail. Enjoy :) 19 quit=Node('Quit', group=9999)( 16 20 Action('Quit', do_quit), 17 21 ), 18 22 cat=Node('Concatenate files')( 19 files=File('File to concatenate', traversals=0)( 23 # This matches a file any number of times... 24 # Note how the example matched any file. If we add the following... 25 # Next, we'll restrict the number of files to 2... 26 files=File('File to concatenate', traversals=2, includes=['*.py'])( 20 27 Action('Concatenate files', do_cat), 28 # This jumps back to the parent (files) node 21 29 Alias('..'), 30 # Now let's see it in action... 22 31 ), 23 32 ), cly/trunk/.todo
r413 r425 1 <todo version="0.1. 19">1 <todo version="0.1.20"> 2 2 <title> 3 3 CLY … … 9 9 Add XPath support: eg. grammar.find_all('//action') 10 10 </note> 11 <note priority="medium" time="1179508609"> 12 console.textwrap() has issues 13 </note> 14 <note priority="medium" time="1179509575"> 15 Allow with_context to be specified per-parser. 16 </note> 11 17 </todo>
