Changeset 132 for pyyaml/trunk/lib/yaml/emitter.py
- Timestamp:
- 04/09/06 15:51:02 (7 years ago)
- File:
-
- 1 edited
-
pyyaml/trunk/lib/yaml/emitter.py (modified) (17 diffs)
Legend:
- Unmodified
- Added
- Removed
-
pyyaml/trunk/lib/yaml/emitter.py
r131 r132 15 15 pass 16 16 17 class ScalarAnalysis: 18 def __init__(self, scalar, empty, multiline, 19 allow_flow_plain, allow_block_plain, 20 allow_single_quoted, allow_double_quoted, allow_block): 21 self.scalar = scalar 22 self.empty = empty 23 self.multiline = multiline 24 self.allow_flow_plain = allow_flow_plain 25 self.allow_block_plain = allow_block_plain 26 self.allow_single_quoted = allow_single_quoted 27 self.allow_double_quoted = allow_double_quoted 28 self.allow_block = allow_block 29 17 30 class Emitter: 18 31 … … 54 67 # Characteristics of the last emitted character: 55 68 # - current position. 56 # - is it a line break?57 69 # - is it a whitespace? 58 70 # - is it an indention character … … 70 82 self.tag_prefixes = None 71 83 72 # Scalar analysis. 73 self.analysis = None 84 # Analyses cache. 85 self.anchor_text = None 86 self.tag_text = None 87 self.scalar_analysis = None 88 self.scalar_style = None 74 89 75 90 def emit(self, event): 76 if self.events: 77 self.events.append(event) 78 event = self.events.pop(0) 79 self.event = event 80 if self.need_more_events(): 81 self.event.insert(0, event) 82 return 83 self.state() 84 self.event = None 91 self.events.append(event) 92 while not self.need_more_events(): 93 self.event = self.events.pop(0) 94 self.state() 95 self.event = None 85 96 86 97 # In some cases, we wait for a few next events before emitting. 87 98 88 99 def need_more_events(self): 89 if isinstance(self.event, DocumentStartEvent): 100 if not self.events: 101 return True 102 event = self.events[0] 103 if isinstance(event, DocumentStartEvent): 90 104 return self.need_events(1) 91 elif isinstance( self.event, SequenceStartEvent):105 elif isinstance(event, SequenceStartEvent): 92 106 return self.need_events(2) 93 elif isinstance( self.event, MappingStartEvent):107 elif isinstance(event, MappingStartEvent): 94 108 return self.need_events(3) 95 109 else: … … 98 112 def need_events(self, count): 99 113 level = 0 100 for event in self.events :101 if isinstance(event, (DocumentStart , CollectionStart)):114 for event in self.events[1:]: 115 if isinstance(event, (DocumentStartEvent, CollectionStartEvent)): 102 116 level += 1 103 elif isinstance(event, (DocumentEnd , CollectionEnd)):117 elif isinstance(event, (DocumentEndEvent, CollectionEndEvent)): 104 118 level -= 1 105 elif isinstance(event, StreamEnd ):119 elif isinstance(event, StreamEndEvent): 106 120 level = -1 107 121 if level < 0: 108 122 return False 109 return (len(self.events) < count )123 return (len(self.events) < count+1) 110 124 111 125 def increase_indent(self, flow=False, indentless=False): … … 125 139 def expect_stream_start(self): 126 140 if isinstance(self.event, StreamStartEvent): 127 self.encoding = event.encoding128 self.canonical = event.canonical141 self.encoding = self.event.encoding 142 self.canonical = self.event.canonical 129 143 if self.event.indent and self.event.indent > 1: 130 144 self.best_indent = self.event.indent … … 150 164 if isinstance(self.event, DocumentStartEvent): 151 165 if self.event.version: 152 self.write_version_directive(self.event.version) 166 version_text = self.analyze_version(self.event.version) 167 self.write_version_directive(version_text) 153 168 self.tag_prefixes = self.DEFAULT_TAG_PREFIXES.copy() 154 169 if self.event.tags: 155 for handle in self.event.tags: 170 handles = self.event.tags.keys() 171 handles.sort() 172 for handle in handles: 156 173 prefix = self.event.tags[handle] 157 174 self.tag_prefixes[prefix] = handle 158 self.write_tag_directive(handle, prefix) 159 implicit = (first and self.event.implicit and not self.canonical 175 handle_text = self.analyze_tag_handle(handle) 176 prefix_text = self.analyze_tag_prefix(prefix) 177 self.write_tag_directive(handle_text, prefix_text) 178 implicit = (first and not self.event.explicit and not self.canonical 160 179 and not self.event.version and not self.event.tags 161 and not self.check_ next_empty_scalar())180 and not self.check_empty_document()) 162 181 if not implicit: 163 182 self.write_indent() … … 176 195 if isinstance(self.event, DocumentEndEvent): 177 196 self.write_indent() 178 if not event.implicit:197 if self.event.explicit: 179 198 self.write_indicator(u'...', True) 180 199 self.write_indent() … … 185 204 186 205 def expect_document_root(self): 206 self.states.append(self.expect_document_end) 187 207 self.expect_node(root=True) 188 208 … … 197 217 if isinstance(self.event, AliasEvent): 198 218 self.expect_alias() 199 elif isinstance( event, (ScalarEvent, CollectionEvent)):200 self.process_anchor( )219 elif isinstance(self.event, (ScalarEvent, CollectionStartEvent)): 220 self.process_anchor(u'&') 201 221 self.process_tag() 202 222 if isinstance(self.event, ScalarEvent): 203 223 self.expect_scalar() 204 elif isinstance(self.event, Sequence Event):224 elif isinstance(self.event, SequenceStartEvent): 205 225 if self.flow_level or self.canonical or self.event.flow_style \ 206 226 or self.check_empty_sequence(): … … 208 228 else: 209 229 self.expect_block_sequence() 210 elif isinstance(self.event, Mapping Event):230 elif isinstance(self.event, MappingStartEvent): 211 231 if self.flow_level or self.canonical or self.event.flow_style \ 212 232 or self.check_empty_mapping(): … … 218 238 219 239 def expect_alias(self): 220 self.write_anchor(u'*', self.event.anchor) 240 if self.event.anchor is None: 241 raise EmitterError("anchor is not specified for alias") 242 self.process_anchor(u'*') 221 243 self.state = self.states.pop() 222 244 … … 351 373 352 374 def expect_block_mapping_key(self, first=False): 353 if not first and isinstance(self.event, SequenceEndEvent):375 if not first and isinstance(self.event, MappingEndEvent): 354 376 self.indent = self.indents.pop() 355 377 self.state = self.states.pop() … … 375 397 self.expect_node(mapping=True) 376 398 399 # Checkers. 400 401 def check_empty_sequence(self): 402 return (isinstance(self.event, SequenceStartEvent) and self.events 403 and isinstance(self.events[0], SequenceEndEvent)) 404 405 def check_empty_mapping(self): 406 return (isinstance(self.event, MappingStartEvent) and self.events 407 and isinstance(self.events[0], MappingEndEvent)) 408 409 def check_empty_document(self): 410 if not isinstance(self.event, DocumentStartEvent) or not self.events: 411 return False 412 event = self.events[0] 413 return (isinstance(event, ScalarEvent) and event.anchor is None 414 and event.tag is None and event.implicit and event.value == u'') 415 416 def check_simple_key(self): 417 length = 0 418 if isinstance(self.event, NodeEvent) and self.event.anchor is not None: 419 if self.anchor_text is None: 420 self.anchor_text = self.analyze_anchor(self.event.anchor) 421 length += len(self.anchor_text) 422 if isinstance(self.event, (ScalarEvent, CollectionStartEvent)) \ 423 and self.event.tag is not None: 424 if self.tag_text is None: 425 self.tag_text = self.analyze_tag(self.event.tag) 426 length += len(self.tag_text) 427 if isinstance(self.event, ScalarEvent): 428 if self.scalar_analysis is None: 429 self.scalar_analysis = self.analyze_scalar(self.event.value) 430 length += len(self.scalar_analysis.scalar) 431 return (length < 128 and (isinstance(self.event, AliasEvent) 432 or (isinstance(self.event, ScalarEvent) and not self.scalar_analysis.multiline) 433 or self.check_empty_sequence() or self.check_empty_mapping())) 434 435 # Anchor, Tag, and Scalar processors. 436 437 def process_anchor(self, indicator): 438 if self.event.anchor is None: 439 return 440 if self.anchor_text is None: 441 self.anchor_text = self.analyze_anchor(self.event.anchor) 442 if self.anchor_text: 443 self.write_indicator(indicator+self.anchor_text, True) 444 self.anchor_text = None 445 446 def process_tag(self): 447 if self.event.tag is None: 448 return 449 if isinstance(self.event, ScalarEvent) and self.best_scalar_style() == '': 450 return 451 if self.tag_text is None: 452 self.tag_text = self.analyze_tag(self.event.tag) 453 if self.tag_text: 454 self.write_indicator(self.tag_text, True) 455 self.tag_text = None 456 457 def best_scalar_style(self): 458 if self.scalar_analysis is None: 459 self.scalar_analysis = self.analyze_scalar(self.event.value) 460 if self.canonical: 461 return '"' 462 if (self.event.implicit and not self.event.style 463 and ((self.flow_level and self.scalar_analysis.allow_flow_plain) 464 or (not self.flow_level and self.scalar_analysis.allow_block_plain)) 465 and (len(self.scalar_analysis.scalar) > 0 466 or (not self.flow_level and not self.simple_key_context))): 467 return '' 468 elif self.event.style == '\'' and self.scalar_analysis.allow_single_quoted: 469 return '\'' 470 elif self.event.style in ['|', '>'] and not self.flow_level and self.scalar_analysis.allow_block: 471 return self.event.style 472 else: 473 return '"' 474 return style 475 476 def process_scalar(self): 477 if self.scalar_analysis is None: 478 self.scalar_analysis = self.analyze_scalar(self.event.value) 479 style = self.best_scalar_style() 480 if self.scalar_analysis.multiline and not self.simple_key_context \ 481 and style not in ['|', '>']: 482 self.write_indent() 483 if style == '"': 484 self.write_double_quoted(self.scalar_analysis.scalar, 485 split=(not self.simple_key_context)) 486 elif style == '\'': 487 self.write_single_quoted(self.scalar_analysis.scalar, 488 split=(not self.simple_key_context)) 489 elif style == '>': 490 self.write_folded(self.scalar_analysis.scalar) 491 elif style == '|': 492 self.write_literal(self.scalar_analysis.scalar) 493 else: 494 self.write_plain(self.scalar_analysis.scalar, 495 split=(not self.simple_key_context)) 496 self.scalar_analysis = None 497 498 # Analyzers. 499 500 def analyze_version(self, version): 501 major, minor = version 502 if major != 1: 503 raise EmitterError("unsupported YAML version: %d.%d" % (major, minor)) 504 return u'%d.%d' % (major, minor) 505 506 def analyze_tag_handle(self, handle): 507 if not handle: 508 raise EmitterError("tag handle must not be empty") 509 if handle[0] != u'!' or handle[-1] != u'!': 510 raise EmitterError("tag handle must start and end with '!': %r" 511 % (handle.encode('utf-8'))) 512 for ch in handle[1:-1]: 513 if not (u'0' <= ch <= u'9' or u'A' <= ch <= 'Z' or u'a' <= ch <= 'z' \ 514 or ch in u'-_'): 515 raise EmitterError("invalid character %r in the tag handle: %r" 516 % (ch.encode('utf-8'), handle.encode('utf-8'))) 517 return handle 518 519 def analyze_tag_prefix(self, prefix): 520 if not prefix: 521 raise EmitterError("tag prefix must not be empty") 522 chunks = [] 523 start = end = 0 524 if prefix[0] == u'!': 525 end = 1 526 while end < len(prefix): 527 ch = prefix[end] 528 if u'0' <= ch <= u'9' or u'A' <= ch <= 'Z' or u'a' <= ch <= 'z' \ 529 or ch in u'-;/?!:@&=+$,_.~*\'()[]': 530 end += 1 531 else: 532 if start < end: 533 chunks.append(prefix[start:end]) 534 start = end = end+1 535 data = ch.encode('utf-8') 536 for ch in data: 537 chunks.append(u'%%%02X' % ord(ch)) 538 if start < end: 539 chunks.append(prefix[start:end]) 540 return u''.join(chunks) 541 542 def analyze_tag(self, tag): 543 if not tag: 544 raise EmitterError("tag must not be empty") 545 handle = None 546 suffix = tag 547 for prefix in self.tag_prefixes: 548 if tag.startswith(prefix) \ 549 and (prefix == u'!' or len(prefix) < len(tag)): 550 handle = self.tag_prefixes[prefix] 551 suffix = tag[len(prefix):] 552 chunks = [] 553 start = end = 0 554 while end < len(suffix): 555 ch = suffix[end] 556 if u'0' <= ch <= u'9' or u'A' <= ch <= 'Z' or u'a' <= ch <= 'z' \ 557 or ch in u'-;/?:@&=+$,_.~*\'()[]' \ 558 or (ch == u'!' and handle != u'!'): 559 end += 1 560 else: 561 if start < end: 562 chunks.append(suffix[start:end]) 563 start = end = end+1 564 data = ch.encode('utf-8') 565 for ch in data: 566 chunks.append(u'%%%02X' % ord(ch)) 567 if start < end: 568 chunks.append(suffix[start:end]) 569 suffix_text = u''.join(chunks) 570 if handle: 571 return u'%s%s' % (handle, suffix_text) 572 else: 573 return u'!<%s>' % suffix_text 574 575 def analyze_anchor(self, anchor): 576 if not anchor: 577 raise EmitterError("anchor must not be empty") 578 for ch in anchor: 579 if not (u'0' <= ch <= u'9' or u'A' <= ch <= 'Z' or u'a' <= ch <= 'z' \ 580 or ch in u'-_'): 581 raise EmitterError("invalid character %r in the anchor: %r" 582 % (ch.encode('utf-8'), text.encode('utf-8'))) 583 return anchor 584 585 def analyze_scalar(self, scalar): # It begs for refactoring. 586 if not scalar: 587 return ScalarAnalysis(scalar=scalar, empty=True, multiline=False, 588 allow_flow_plain=False, allow_block_plain=True, 589 allow_single_quoted=True, allow_double_quoted=True, 590 allow_block=False) 591 contains_block_indicator = False 592 contains_flow_indicator = False 593 contains_line_breaks = False 594 contains_unicode_characters = False 595 contains_special_characters = False 596 contains_inline_spaces = False # non-space space+ non-space 597 contains_inline_breaks = False # non-space break+ non-space 598 contains_leading_spaces = False # ^ space+ (non-space | $) 599 contains_leading_breaks = False # ^ break+ (non-space | $) 600 contains_trailing_spaces = False # non-space space+ $ 601 contains_trailing_breaks = False # non-space break+ $ 602 contains_inline_breaks_spaces = False # non-space break+ space+ non-space 603 contains_mixed_breaks_spaces = False # anything else 604 if scalar.startswith(u'---') or scalar.startswith(u'...'): 605 contains_block_indicator = True 606 contains_flow_indicator = True 607 first = True 608 last = (len(scalar) == 1) 609 preceeded_by_space = False 610 followed_by_space = (len(scalar) > 1 and 611 scalar[1] in u'\0 \t\r\n\x85\u2028\u2029') 612 spaces = breaks = mixed = leading = False 613 index = 0 614 while index < len(scalar): 615 ch = scalar[index] 616 if first: 617 if ch in u'#,[]{}#&*!|>\'\"%@`': 618 contains_flow_indicator = True 619 contains_block_indicator = True 620 if ch in u'?:': 621 contains_flow_indicator = True 622 if followed_by_space or last: 623 contains_block_indicator = True 624 if ch == u'-' and followed_by_space or last: 625 contains_flow_indicator = True 626 contains_block_indicator = True 627 else: 628 if ch in u',?[]{}': 629 contains_flow_indicator = True 630 if ch == u':': 631 contains_flow_indicator = True 632 if followed_by_space or last: 633 contains_block_indicator = True 634 if ch == u'#' and preceeded_by_space: 635 contains_flow_indicator = True 636 contains_block_indicator = True 637 if ch in u'\n\x85\u2028\u2029': 638 contains_line_breaks = True 639 if not (ch == u'\n' or u'\x20' <= ch <= u'\x7E'): 640 if ch < u'\x80': 641 contains_special_characters = True 642 else: 643 contains_special_characters = True 644 # TODO: We need an option to allow unescaped unicode 645 # characters. 646 contains_unicode_characters = True 647 if ch == u' ': 648 if not spaces and not breaks: 649 leading = first 650 spaces = True 651 elif ch in u'\n\x85\u2028\u2029': 652 if not spaces and not breaks: 653 leading = first 654 breaks = True 655 if spaces: 656 mixed = True 657 if ch not in u' \n\x85\u2028\u2029': 658 if leading: 659 if spaces and breaks: 660 contains_mixed_breaks_spaces = True 661 elif spaces: 662 contains_leading_spaces = True 663 elif breaks: 664 contains_leading_breaks = True 665 else: 666 if mixed: 667 contains_mixed_break_spaces = True 668 elif spaces and breaks: 669 contains_inline_breaks_spaces = True 670 elif spaces: 671 contains_inline_spaces = True 672 elif breaks: 673 contains_inline_breaks = True 674 spaces = breaks = mixed = leading = False 675 elif last: 676 if spaces and breaks: 677 contains_mixed_break_spaces = True 678 elif spaces: 679 if leading: 680 contains_leading_spaces = True 681 else: 682 contains_trailing_spaces = True 683 elif breaks: 684 if leading: 685 contains_leading_breaks = True 686 else: 687 contains_trailing_breaks = True 688 index += 1 689 first = False 690 last = (index+1 == len(scalar)) 691 preceeded_by_space = (ch in u'\0 \t\r\n\x85\u2028\u2029') 692 followed_by_space = (index+1 < len(scalar) and 693 scalar[index+1] in u'\0 \t\r\n\x85\u2028\u2029') 694 allow_flow_plain = not (contains_flow_indicator or contains_special_characters 695 or contains_leading_spaces or contains_leading_breaks 696 or contains_trailing_spaces or contains_trailing_breaks 697 or contains_inline_breaks_spaces or contains_mixed_breaks_spaces) 698 allow_block_plain = not (contains_block_indicator or contains_special_characters 699 or contains_leading_spaces or contains_leading_breaks 700 or contains_trailing_spaces or contains_trailing_breaks 701 or contains_inline_breaks_spaces or contains_mixed_breaks_spaces) 702 allow_single_quoted = not (contains_special_characters 703 or contains_inline_breaks_spaces or contains_mixed_breaks_spaces) 704 allow_double_quoted = True 705 allow_block = not (contains_special_characters 706 or contains_leading_spaces or contains_leading_breaks 707 or contains_trailing_spaces or contains_mixed_breaks_spaces) 708 return ScalarAnalysis(scalar=scalar, empty=False, multiline=contains_line_breaks, 709 allow_flow_plain=allow_flow_plain, allow_block_plain=allow_block_plain, 710 allow_single_quoted=allow_single_quoted, allow_double_quoted=allow_double_quoted, 711 allow_block=allow_block) 712 377 713 # Writers. 378 714 … … 388 724 def write_indicator(self, indicator, need_whitespace, 389 725 whitespace=False, indention=False): 390 if self.whitespace :726 if self.whitespace or not need_whitespace: 391 727 data = indicator 392 728 else: 393 729 data = u' '+indicator 394 self.w ritespace = whitespace730 self.whitespace = whitespace 395 731 self.indention = self.indention and indention 396 732 self.column += len(data) … … 401 737 def write_indent(self): 402 738 indent = self.indent or 0 403 if not self.indention or self.column > indent: 739 if not self.indention or self.column > indent \ 740 or (self.column == indent and not self.whitespace): 404 741 self.write_line_break() 405 742 if self.column < indent: 743 self.whitespace = True 406 744 data = u' '*(indent-self.column) 407 745 self.column = indent … … 410 748 self.writer.write(data) 411 749 412 def write_line_break(self): 413 data = self.best_line_break 750 def write_line_break(self, data=None): 751 if data is None: 752 data = self.best_line_break 414 753 self.whitespace = True 415 754 self.indention = True … … 420 759 self.writer.write(data) 421 760 761 def write_version_directive(self, version_text): 762 data = u'%%YAML %s' % version_text 763 if self.encoding: 764 data = data.encode(self.encoding) 765 self.writer.write(data) 766 self.write_line_break() 767 768 def write_tag_directive(self, handle_text, prefix_text): 769 data = u'%%TAG %s %s' % (handle_text, prefix_text) 770 if self.encoding: 771 data = data.encode(self.encoding) 772 self.writer.write(data) 773 self.write_line_break() 774 775 # Scalar writers. 776 777 def write_single_quoted(self, text, split=True): 778 self.write_indicator(u'\'', True) 779 spaces = False 780 breaks = False 781 start = end = 0 782 while end <= len(text): 783 ch = None 784 if end < len(text): 785 ch = text[end] 786 if spaces: 787 if ch is None or ch != u' ': 788 if start+1 == end and self.column > self.best_width and split \ 789 and start != 0 and end != len(text): 790 self.write_indent() 791 else: 792 data = text[start:end] 793 self.column += len(data) 794 if self.encoding: 795 data = data.encode(self.encoding) 796 self.writer.write(data) 797 start = end 798 elif breaks: 799 if ch is None or ch not in u'\n\x85\u2028\u2029': 800 if text[start] == u'\n': 801 self.write_line_break() 802 for br in text[start:end]: 803 if br == u'\n': 804 self.write_line_break() 805 else: 806 self.write_line_break(br) 807 self.write_indent() 808 start = end 809 else: 810 if ch is None or ch in u' \n\x85\u2028\u2029' or ch == u'\'': 811 if start < end: 812 data = text[start:end] 813 self.column += len(data) 814 if self.encoding: 815 data = data.encode(self.encoding) 816 self.writer.write(data) 817 start = end 818 if ch == u'\'': 819 data = u'\'\'' 820 self.column += 2 821 if self.encoding: 822 data = data.encode(self.encoding) 823 self.writer.write(data) 824 start = end + 1 825 if ch is not None: 826 spaces = (ch == u' ') 827 breaks = (ch in u'\n\x85\u2028\u2029') 828 end += 1 829 self.write_indicator(u'\'', False) 830 831 ESCAPE_REPLACEMENTS = { 832 u'\0': u'0', 833 u'\x07': u'a', 834 u'\x08': u'b', 835 u'\x09': u't', 836 u'\x0A': u'n', 837 u'\x0B': u'v', 838 u'\x0C': u'f', 839 u'\x0D': u'r', 840 u'\x1B': u'e', 841 u'\"': u'\"', 842 u'\\': u'\\', 843 u'\x85': u'N', 844 u'\xA0': u'_', 845 u'\u2028': u'L', 846 u'\u2029': u'P', 847 } 848 849 def write_double_quoted(self, text, split=True): 850 self.write_indicator(u'"', True) 851 start = end = 0 852 while end <= len(text): 853 ch = None 854 if end < len(text): 855 ch = text[end] 856 if ch is None or not (u'\x20' <= ch <= u'\x7E') or ch in u'"\\': 857 if start < end: 858 data = text[start:end] 859 self.column += len(data) 860 if self.encoding: 861 data = data.encode(self.encoding) 862 self.writer.write(data) 863 start = end 864 if ch is not None: 865 if ch in self.ESCAPE_REPLACEMENTS: 866 data = u'\\'+self.ESCAPE_REPLACEMENTS[ch] 867 elif ch <= u'\xFF': 868 data = u'\\x%02X' % ord(ch) 869 elif ch <= u'\uFFFF': 870 data = u'\\u%04X' % ord(ch) 871 else: 872 data = u'\\U%08X' % ord(ch) 873 self.column += len(data) 874 if self.encoding: 875 data = data.encode(self.encoding) 876 self.writer.write(data) 877 start = end+1 878 if 0 < end < len(text)-1 and (ch == u' ' or start >= end) \ 879 and self.column+(end-start) > self.best_width and split: 880 data = text[start:end]+u'\\' 881 if start < end: 882 start = end 883 self.column += len(data) 884 if self.encoding: 885 data = data.encode(self.encoding) 886 self.writer.write(data) 887 self.write_indent() 888 self.whitespace = False 889 self.indention = False 890 if ch == u' ': 891 data = u'\\' 892 self.column += len(data) 893 if self.encoding: 894 data = data.encode(self.encoding) 895 self.writer.write(data) 896 end += 1 897 self.write_indicator(u'"', False) 898 899 def determine_chomp(self, text): 900 tail = text[-2:] 901 while len(tail) < 2: 902 tail = u' '+tail 903 if tail[-1] in u'\n\x85\u2028\u2029': 904 if tail[-2] in u'\n\x85\u2028\u2029': 905 return u'+' 906 else: 907 return u'' 908 else: 909 return u'-' 910 911 def write_folded(self, text): 912 chomp = self.determine_chomp(text) 913 self.write_indicator(u'>'+chomp, True) 914 self.write_indent() 915 leading_space = False 916 spaces = False 917 breaks = False 918 start = end = 0 919 while end <= len(text): 920 ch = None 921 if end < len(text): 922 ch = text[end] 923 if breaks: 924 if ch is None or ch not in u'\n\x85\u2028\u2029': 925 if not leading_space and ch is not None and ch != u' ' \ 926 and text[start] == u'\n': 927 self.write_line_break() 928 leading_space = (ch == u' ') 929 for br in text[start:end]: 930 if br == u'\n': 931 self.write_line_break() 932 else: 933 self.write_line_break(br) 934 if ch is not None: 935 self.write_indent() 936 start = end 937 elif spaces: 938 if ch != u' ': 939 if start+1 == end and self.column > self.best_width: 940 self.write_indent() 941 else: 942 data = text[start:end] 943 self.column += len(data) 944 if self.encoding: 945 data = data.encode(self.encoding) 946 self.writer.write(data) 947 start = end 948 else: 949 if ch is None or ch in u' \n\x85\u2028\u2029': 950 data = text[start:end] 951 if self.encoding: 952 data = data.encode(self.encoding) 953 self.writer.write(data) 954 if ch is None: 955 self.write_line_break() 956 start = end 957 if ch is not None: 958 breaks = (ch in u'\n\x85\u2028\u2029') 959 spaces = (ch == u' ') 960 end += 1 961 962 def write_literal(self, text): 963 chomp = self.determine_chomp(text) 964 self.write_indicator(u'|'+chomp, True) 965 self.write_indent() 966 breaks = False 967 start = end = 0 968 while end <= len(text): 969 ch = None 970 if end < len(text): 971 ch = text[end] 972 if breaks: 973 if ch is None or ch not in u'\n\x85\u2028\u2029': 974 for br in text[start:end]: 975 if br == u'\n': 976 self.write_line_break() 977 else: 978 self.write_line_break(br) 979 if ch is not None: 980 self.write_indent() 981 start = end 982 else: 983 if ch is None or ch in u'\n\x85\u2028\u2029': 984 data = text[start:end] 985 if self.encoding: 986 data = data.encode(self.encoding) 987 self.writer.write(data) 988 if ch is None: 989 self.write_line_break() 990 start = end 991 if ch is not None: 992 breaks = (ch in u'\n\x85\u2028\u2029') 993 end += 1 994 995 def write_plain(self, text, split=True): 996 if not text: 997 return 998 if not self.whitespace: 999 data = u' ' 1000 self.column += len(data) 1001 if self.encoding: 1002 data = data.encode(self.encoding) 1003 self.writer.write(data) 1004 self.writespace = False 1005 self.indention = False 1006 spaces = False 1007 breaks = False 1008 start = end = 0 1009 while end <= len(text): 1010 ch = None 1011 if end < len(text): 1012 ch = text[end] 1013 if spaces: 1014 if ch != u' ': 1015 if start+1 == end and self.column > self.best_width and split: 1016 self.write_indent() 1017 self.writespace = False 1018 self.indention = False 1019 else: 1020 data = text[start:end] 1021 self.column += len(data) 1022 if self.encoding: 1023 data = data.encode(self.encoding) 1024 self.writer.write(data) 1025 start = end 1026 elif breaks: 1027 if ch not in u'\n\x85\u2028\u2029': 1028 if text[start] == u'\n': 1029 self.write_line_break() 1030 for br in text[start:end]: 1031 if br == u'\n': 1032 self.write_line_break() 1033 else: 1034 self.write_line_break(br) 1035 self.write_indent() 1036 self.whitespace = False 1037 self.indention = False 1038 start = end 1039 else: 1040 if ch is None or ch in u' \n\x85\u2028\u2029': 1041 data = text[start:end] 1042 self.column += len(data) 1043 if self.encoding: 1044 data = data.encode(self.encoding) 1045 self.writer.write(data) 1046 start = end 1047 if ch is not None: 1048 spaces = (ch == u' ') 1049 breaks = (ch in u'\n\x85\u2028\u2029') 1050 end += 1 1051
Note: See TracChangeset
for help on using the changeset viewer.
