blob: 729ec93ec47e629ab12e20ad586dc311e882209c [file] [log] [blame]
Guido van Rossum94e82ce1999-01-04 13:04:54 +00001# Extension to format a paragraph
2
3import string
4import re
5
6class FormatParagraph:
7
8 menudefs = [
9 ('edit', [
10 ('Format Paragraph', '<<format-paragraph>>'),
11 ])
12 ]
13
14 keydefs = {
15 '<<format-paragraph>>': ['<Alt-q>'],
16 }
17
18 def __init__(self, editwin):
19 self.editwin = editwin
20
21 def format_paragraph_event(self, event):
22 text = self.editwin.text
23 try:
24 first = text.index("sel.first")
25 last = text.index("sel.last")
26 except TclError:
27 first = last = None
28 if first and last:
29 data = text.get(first, last)
30 else:
31 first, last, data = find_paragraph(text, text.index("insert"))
32 newdata = reformat_paragraph(data)
33 text.tag_remove("sel", "1.0", "end")
34 if newdata != data:
35 text.mark_set("insert", first)
36 text.delete(first, last)
37 text.insert(first, newdata)
38 else:
39 text.mark_set("insert", last)
40 text.see("insert")
41
42def find_paragraph(text, mark):
43 lineno, col = map(int, string.split(mark, "."))
44 line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
45 while is_all_white(line):
46 lineno = lineno + 1
47 line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
48 first_lineno = lineno
49 while not is_all_white(line):
50 lineno = lineno + 1
51 line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
52 last = "%d.0" % lineno
53 # Search back to beginning of paragraph
54 lineno = first_lineno - 1
55 line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
56 while not is_all_white(line):
57 lineno = lineno - 1
58 line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
59 first = "%d.0" % (lineno+1)
60 return first, last, text.get(first, last)
61
62def reformat_paragraph(data, limit=72):
63 lines = string.split(data, "\n")
64 i = 0
65 n = len(lines)
66 while i < n and is_all_white(lines[i]):
67 i = i+1
68 if i >= n:
69 return data
70 indent1 = get_indent(lines[i])
71 if i+1 < n and not is_all_white(lines[i+1]):
72 indent2 = get_indent(lines[i+1])
73 else:
74 indent2 = indent1
75 new = lines[:i]
76 partial = indent1
77 while i < n and not is_all_white(lines[i]):
78 # XXX Should take double space after period (etc.) into account
79 words = re.split("(\s+)", lines[i])
80 for j in range(0, len(words), 2):
81 word = words[j]
82 if not word:
83 continue # Can happen when line ends in whitespace
84 if len(string.expandtabs(partial + word)) > limit and \
85 partial != indent1:
86 new.append(string.rstrip(partial))
87 partial = indent2
88 partial = partial + word + " "
89 if j+1 < len(words) and words[j+1] != " ":
90 partial = partial + " "
91 i = i+1
92 new.append(string.rstrip(partial))
93 # XXX Should reformat remaining paragraphs as well
94 new.extend(lines[i:])
95 return string.join(new, "\n")
96
97def is_all_white(line):
98 return re.match(r"^\s*$", line) is not None
99
100def get_indent(line):
101 return re.match(r"^(\s*)", line).group()