blob: e17f54c51e613bdb3b79b68c5e758ff22df52e72 [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)
Guido van Rossum318a70d1999-05-03 15:49:52 +000040 text.undo_block_start()
Guido van Rossum94e82ce1999-01-04 13:04:54 +000041 text.delete(first, last)
42 text.insert(first, newdata)
Guido van Rossum318a70d1999-05-03 15:49:52 +000043 text.undo_block_stop()
Guido van Rossum94e82ce1999-01-04 13:04:54 +000044 else:
45 text.mark_set("insert", last)
46 text.see("insert")
47
48def find_paragraph(text, mark):
49 lineno, col = map(int, string.split(mark, "."))
50 line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
Guido van Rossum1e899cd1999-01-04 21:19:09 +000051 while text.compare("%d.0" % lineno, "<", "end") and is_all_white(line):
Guido van Rossum94e82ce1999-01-04 13:04:54 +000052 lineno = lineno + 1
53 line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
54 first_lineno = lineno
55 while not is_all_white(line):
56 lineno = lineno + 1
57 line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
58 last = "%d.0" % lineno
59 # Search back to beginning of paragraph
60 lineno = first_lineno - 1
61 line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
Guido van Rossume911c3e1999-01-04 16:34:41 +000062 while lineno > 0 and not is_all_white(line):
Guido van Rossum94e82ce1999-01-04 13:04:54 +000063 lineno = lineno - 1
64 line = text.get("%d.0" % lineno, "%d.0 lineend" % lineno)
65 first = "%d.0" % (lineno+1)
66 return first, last, text.get(first, last)
67
Guido van Rossum629082e1999-01-07 00:12:15 +000068def reformat_paragraph(data, limit=70):
Guido van Rossum94e82ce1999-01-04 13:04:54 +000069 lines = string.split(data, "\n")
70 i = 0
71 n = len(lines)
72 while i < n and is_all_white(lines[i]):
73 i = i+1
74 if i >= n:
75 return data
76 indent1 = get_indent(lines[i])
77 if i+1 < n and not is_all_white(lines[i+1]):
78 indent2 = get_indent(lines[i+1])
79 else:
80 indent2 = indent1
81 new = lines[:i]
82 partial = indent1
83 while i < n and not is_all_white(lines[i]):
84 # XXX Should take double space after period (etc.) into account
85 words = re.split("(\s+)", lines[i])
86 for j in range(0, len(words), 2):
87 word = words[j]
88 if not word:
89 continue # Can happen when line ends in whitespace
90 if len(string.expandtabs(partial + word)) > limit and \
91 partial != indent1:
92 new.append(string.rstrip(partial))
93 partial = indent2
94 partial = partial + word + " "
95 if j+1 < len(words) and words[j+1] != " ":
96 partial = partial + " "
97 i = i+1
98 new.append(string.rstrip(partial))
99 # XXX Should reformat remaining paragraphs as well
100 new.extend(lines[i:])
101 return string.join(new, "\n")
102
103def is_all_white(line):
104 return re.match(r"^\s*$", line) is not None
105
106def get_indent(line):
107 return re.match(r"^(\s*)", line).group()