blob: f8827e7615872423e3e139c2ba308cff680bf62c [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 }
Guido van Rossume911c3e1999-01-04 16:34:41 +000017
18 unix_keydefs = {
19 '<<format-paragraph>>': ['<Meta-q>'],
20 }
Guido van Rossum94e82ce1999-01-04 13:04:54 +000021
22 def __init__(self, editwin):
23 self.editwin = editwin
24
25 def format_paragraph_event(self, event):
26 text = self.editwin.text
27 try:
28 first = text.index("sel.first")
29 last = text.index("sel.last")
30 except TclError:
31 first = last = None
32 if first and last:
33 data = text.get(first, last)
34 else:
35 first, last, data = find_paragraph(text, text.index("insert"))
36 newdata = reformat_paragraph(data)
37 text.tag_remove("sel", "1.0", "end")
38 if newdata != data:
39 text.mark_set("insert", first)
40 text.delete(first, last)
41 text.insert(first, newdata)
42 else:
43 text.mark_set("insert", last)
44 text.see("insert")
45
46def find_paragraph(text, mark):
47 lineno, col = map(int, string.split(mark, "."))
48 line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
Guido van Rossum1e899cd1999-01-04 21:19:09 +000049 while text.compare("%d.0" % lineno, "<", "end") and is_all_white(line):
Guido van Rossum94e82ce1999-01-04 13:04:54 +000050 lineno = lineno + 1
51 line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
52 first_lineno = lineno
53 while not is_all_white(line):
54 lineno = lineno + 1
55 line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
56 last = "%d.0" % lineno
57 # Search back to beginning of paragraph
58 lineno = first_lineno - 1
59 line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
Guido van Rossume911c3e1999-01-04 16:34:41 +000060 while lineno > 0 and not is_all_white(line):
Guido van Rossum94e82ce1999-01-04 13:04:54 +000061 lineno = lineno - 1
62 line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
63 first = "%d.0" % (lineno+1)
64 return first, last, text.get(first, last)
65
Guido van Rossum629082e1999-01-07 00:12:15 +000066def reformat_paragraph(data, limit=70):
Guido van Rossum94e82ce1999-01-04 13:04:54 +000067 lines = string.split(data, "\n")
68 i = 0
69 n = len(lines)
70 while i < n and is_all_white(lines[i]):
71 i = i+1
72 if i >= n:
73 return data
74 indent1 = get_indent(lines[i])
75 if i+1 < n and not is_all_white(lines[i+1]):
76 indent2 = get_indent(lines[i+1])
77 else:
78 indent2 = indent1
79 new = lines[:i]
80 partial = indent1
81 while i < n and not is_all_white(lines[i]):
82 # XXX Should take double space after period (etc.) into account
83 words = re.split("(\s+)", lines[i])
84 for j in range(0, len(words), 2):
85 word = words[j]
86 if not word:
87 continue # Can happen when line ends in whitespace
88 if len(string.expandtabs(partial + word)) > limit and \
89 partial != indent1:
90 new.append(string.rstrip(partial))
91 partial = indent2
92 partial = partial + word + " "
93 if j+1 < len(words) and words[j+1] != " ":
94 partial = partial + " "
95 i = i+1
96 new.append(string.rstrip(partial))
97 # XXX Should reformat remaining paragraphs as well
98 new.extend(lines[i:])
99 return string.join(new, "\n")
100
101def is_all_white(line):
102 return re.match(r"^\s*$", line) is not None
103
104def get_indent(line):
105 return re.match(r"^(\s*)", line).group()