Ignore:
Timestamp:
Mar 19, 2014, 11:31:01 PM (11 years ago)
Author:
dmik
Message:

python: Merge vendor 2.7.6 to trunk.

Location:
python/trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • python/trunk

  • python/trunk/Lib/idlelib/FormatParagraph.py

    r2 r391  
    1 # Extension to format a paragraph
     1"""Extension to format a paragraph or selection to a max width.
    22
    3 # Does basic, standard text formatting, and also understands Python
    4 # comment blocks. Thus, for editing Python source code, this
    5 # extension is really only suitable for reformatting these comment
    6 # blocks or triple-quoted strings.
     3Does basic, standard text formatting, and also understands Python
     4comment blocks. Thus, for editing Python source code, this
     5extension is really only suitable for reformatting these comment
     6blocks or triple-quoted strings.
    77
    8 # Known problems with comment reformatting:
    9 # * If there is a selection marked, and the first line of the
    10 #   selection is not complete, the block will probably not be detected
    11 #   as comments, and will have the normal "text formatting" rules
    12 #   applied.
    13 # * If a comment block has leading whitespace that mixes tabs and
    14 #   spaces, they will not be considered part of the same block.
    15 # * Fancy comments, like this bulleted list, arent handled :-)
     8Known problems with comment reformatting:
     9* If there is a selection marked, and the first line of the
     10  selection is not complete, the block will probably not be detected
     11  as comments, and will have the normal "text formatting" rules
     12  applied.
     13* If a comment block has leading whitespace that mixes tabs and
     14  spaces, they will not be considered part of the same block.
     15* Fancy comments, like this bulleted list, aren't handled :-)
     16"""
    1617
    1718import re
    18 from configHandler import idleConf
     19from idlelib.configHandler import idleConf
    1920
    2021class FormatParagraph:
     
    3334
    3435    def format_paragraph_event(self, event):
    35         maxformatwidth = int(idleConf.GetOption('main','FormatParagraph','paragraph'))
     36        """Formats paragraph to a max width specified in idleConf.
     37
     38        If text is selected, format_paragraph_event will start breaking lines
     39        at the max width, starting from the beginning selection.
     40
     41        If no text is selected, format_paragraph_event uses the current
     42        cursor location to determine the paragraph (lines of text surrounded
     43        by blank lines) and formats it.
     44        """
     45        maxformatwidth = idleConf.GetOption(
     46                'main', 'FormatParagraph', 'paragraph', type='int')
    3647        text = self.editwin.text
    3748        first, last = self.editwin.get_selection_indices()
    3849        if first and last:
    3950            data = text.get(first, last)
    40             comment_header = ''
     51            comment_header = get_comment_header(data)
    4152        else:
    4253            first, last, comment_header, data = \
    4354                    find_paragraph(text, text.index("insert"))
    4455        if comment_header:
    45             # Reformat the comment lines - convert to text sans header.
    46             lines = data.split("\n")
    47             lines = map(lambda st, l=len(comment_header): st[l:], lines)
    48             data = "\n".join(lines)
    49             # Reformat to maxformatwidth chars or a 20 char width, whichever is greater.
    50             format_width = max(maxformatwidth - len(comment_header), 20)
    51             newdata = reformat_paragraph(data, format_width)
    52             # re-split and re-insert the comment header.
    53             newdata = newdata.split("\n")
    54             # If the block ends in a \n, we dont want the comment
    55             # prefix inserted after it. (Im not sure it makes sense to
    56             # reformat a comment block that isnt made of complete
    57             # lines, but whatever!)  Can't think of a clean soltution,
    58             # so we hack away
    59             block_suffix = ""
    60             if not newdata[-1]:
    61                 block_suffix = "\n"
    62                 newdata = newdata[:-1]
    63             builder = lambda item, prefix=comment_header: prefix+item
    64             newdata = '\n'.join(map(builder, newdata)) + block_suffix
     56            newdata = reformat_comment(data, maxformatwidth, comment_header)
    6557        else:
    66             # Just a normal text format
    6758            newdata = reformat_paragraph(data, maxformatwidth)
    6859        text.tag_remove("sel", "1.0", "end")
     60
    6961        if newdata != data:
    7062            text.mark_set("insert", first)
     
    7971
    8072def find_paragraph(text, mark):
     73    """Returns the start/stop indices enclosing the paragraph that mark is in.
     74
     75    Also returns the comment format string, if any, and paragraph of text
     76    between the start/stop indices.
     77    """
    8178    lineno, col = map(int, mark.split("."))
    82     line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
     79    line = text.get("%d.0" % lineno, "%d.end" % lineno)
     80
     81    # Look for start of next paragraph if the index passed in is a blank line
    8382    while text.compare("%d.0" % lineno, "<", "end") and is_all_white(line):
    8483        lineno = lineno + 1
    85         line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
     84        line = text.get("%d.0" % lineno, "%d.end" % lineno)
    8685    first_lineno = lineno
    8786    comment_header = get_comment_header(line)
    8887    comment_header_len = len(comment_header)
     88
     89    # Once start line found, search for end of paragraph (a blank line)
    8990    while get_comment_header(line)==comment_header and \
    9091              not is_all_white(line[comment_header_len:]):
    9192        lineno = lineno + 1
    92         line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
     93        line = text.get("%d.0" % lineno, "%d.end" % lineno)
    9394    last = "%d.0" % lineno
    94     # Search back to beginning of paragraph
     95
     96    # Search back to beginning of paragraph (first blank line before)
    9597    lineno = first_lineno - 1
    96     line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
     98    line = text.get("%d.0" % lineno, "%d.end" % lineno)
    9799    while lineno > 0 and \
    98100              get_comment_header(line)==comment_header and \
    99101              not is_all_white(line[comment_header_len:]):
    100102        lineno = lineno - 1
    101         line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
     103        line = text.get("%d.0" % lineno, "%d.end" % lineno)
    102104    first = "%d.0" % (lineno+1)
     105
    103106    return first, last, comment_header, text.get(first, last)
    104107
     108# This should perhaps be replaced with textwrap.wrap
    105109def reformat_paragraph(data, limit):
     110    """Return data reformatted to specified width (limit)."""
    106111    lines = data.split("\n")
    107112    i = 0
     
    126131                continue # Can happen when line ends in whitespace
    127132            if len((partial + word).expandtabs()) > limit and \
    128                partial != indent1:
     133                   partial != indent1:
    129134                new.append(partial.rstrip())
    130135                partial = indent2
     
    138143    return "\n".join(new)
    139144
     145def reformat_comment(data, limit, comment_header):
     146    """Return data reformatted to specified width with comment header."""
     147
     148    # Remove header from the comment lines
     149    lc = len(comment_header)
     150    data = "\n".join(line[lc:] for line in data.split("\n"))
     151    # Reformat to maxformatwidth chars or a 20 char width,
     152    # whichever is greater.
     153    format_width = max(limit - len(comment_header), 20)
     154    newdata = reformat_paragraph(data, format_width)
     155    # re-split and re-insert the comment header.
     156    newdata = newdata.split("\n")
     157    # If the block ends in a \n, we dont want the comment prefix
     158    # inserted after it. (Im not sure it makes sense to reformat a
     159    # comment block that is not made of complete lines, but whatever!)
     160    # Can't think of a clean solution, so we hack away
     161    block_suffix = ""
     162    if not newdata[-1]:
     163        block_suffix = "\n"
     164        newdata = newdata[:-1]
     165    return '\n'.join(comment_header+line for line in newdata) + block_suffix
     166
    140167def is_all_white(line):
     168    """Return True if line is empty or all whitespace."""
     169
    141170    return re.match(r"^\s*$", line) is not None
    142171
    143172def get_indent(line):
    144     return re.match(r"^(\s*)", line).group()
     173    """Return the initial space or tab indent of line."""
     174    return re.match(r"^([ \t]*)", line).group()
    145175
    146176def get_comment_header(line):
    147     m = re.match(r"^(\s*#*)", line)
     177    """Return string with leading whitespace and '#' from line or ''.
     178
     179    A null return indicates that the line is not a comment line. A non-
     180    null return, such as '    #', will be used to find the other lines of
     181    a comment block with the same  indent.
     182    """
     183    m = re.match(r"^([ \t]*#*)", line)
    148184    if m is None: return ""
    149185    return m.group(1)
     186
     187if __name__ == "__main__":
     188    from test import support; support.use_resources = ['gui']
     189    import unittest
     190    unittest.main('idlelib.idle_test.test_formatparagraph',
     191            verbosity=2, exit=False)
Note: See TracChangeset for help on using the changeset viewer.