Changeset 391 for python/trunk/Lib/idlelib/FormatParagraph.py
- Timestamp:
- Mar 19, 2014, 11:31:01 PM (11 years ago)
- Location:
- python/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
python/trunk
-
Property svn:mergeinfo
set to
/python/vendor/Python-2.7.6 merged eligible /python/vendor/current merged eligible
-
Property svn:mergeinfo
set to
-
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. 2 2 3 #Does basic, standard text formatting, and also understands Python4 # comment blocks.Thus, for editing Python source code, this5 #extension is really only suitable for reformatting these comment6 #blocks or triple-quoted strings.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. 7 7 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 :-) 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, aren't handled :-) 16 """ 16 17 17 18 import re 18 from configHandler import idleConf19 from idlelib.configHandler import idleConf 19 20 20 21 class FormatParagraph: … … 33 34 34 35 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') 36 47 text = self.editwin.text 37 48 first, last = self.editwin.get_selection_indices() 38 49 if first and last: 39 50 data = text.get(first, last) 40 comment_header = ''51 comment_header = get_comment_header(data) 41 52 else: 42 53 first, last, comment_header, data = \ 43 54 find_paragraph(text, text.index("insert")) 44 55 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) 65 57 else: 66 # Just a normal text format67 58 newdata = reformat_paragraph(data, maxformatwidth) 68 59 text.tag_remove("sel", "1.0", "end") 60 69 61 if newdata != data: 70 62 text.mark_set("insert", first) … … 79 71 80 72 def 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 """ 81 78 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 83 82 while text.compare("%d.0" % lineno, "<", "end") and is_all_white(line): 84 83 lineno = lineno + 1 85 line = text.get("%d.0" % lineno, "%d. 0 lineend" % lineno)84 line = text.get("%d.0" % lineno, "%d.end" % lineno) 86 85 first_lineno = lineno 87 86 comment_header = get_comment_header(line) 88 87 comment_header_len = len(comment_header) 88 89 # Once start line found, search for end of paragraph (a blank line) 89 90 while get_comment_header(line)==comment_header and \ 90 91 not is_all_white(line[comment_header_len:]): 91 92 lineno = lineno + 1 92 line = text.get("%d.0" % lineno, "%d. 0 lineend" % lineno)93 line = text.get("%d.0" % lineno, "%d.end" % lineno) 93 94 last = "%d.0" % lineno 94 # Search back to beginning of paragraph 95 96 # Search back to beginning of paragraph (first blank line before) 95 97 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) 97 99 while lineno > 0 and \ 98 100 get_comment_header(line)==comment_header and \ 99 101 not is_all_white(line[comment_header_len:]): 100 102 lineno = lineno - 1 101 line = text.get("%d.0" % lineno, "%d. 0 lineend" % lineno)103 line = text.get("%d.0" % lineno, "%d.end" % lineno) 102 104 first = "%d.0" % (lineno+1) 105 103 106 return first, last, comment_header, text.get(first, last) 104 107 108 # This should perhaps be replaced with textwrap.wrap 105 109 def reformat_paragraph(data, limit): 110 """Return data reformatted to specified width (limit).""" 106 111 lines = data.split("\n") 107 112 i = 0 … … 126 131 continue # Can happen when line ends in whitespace 127 132 if len((partial + word).expandtabs()) > limit and \ 128 partial != indent1:133 partial != indent1: 129 134 new.append(partial.rstrip()) 130 135 partial = indent2 … … 138 143 return "\n".join(new) 139 144 145 def 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 140 167 def is_all_white(line): 168 """Return True if line is empty or all whitespace.""" 169 141 170 return re.match(r"^\s*$", line) is not None 142 171 143 172 def 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() 145 175 146 176 def 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) 148 184 if m is None: return "" 149 185 return m.group(1) 186 187 if __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.