| | 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 | |
| | 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 | |