mirror of
https://github.com/python/cpython.git
synced 2025-08-23 10:16:01 +00:00
Many improvements dure to Fred Drake
This commit is contained in:
parent
d2560b0f2e
commit
9787bdafe0
1 changed files with 152 additions and 56 deletions
208
Lib/formatter.py
208
Lib/formatter.py
|
@ -2,6 +2,7 @@ import regex
|
||||||
import regsub
|
import regsub
|
||||||
import string
|
import string
|
||||||
import sys
|
import sys
|
||||||
|
from types import StringType
|
||||||
|
|
||||||
|
|
||||||
AS_IS = None
|
AS_IS = None
|
||||||
|
@ -12,66 +13,94 @@ class NullFormatter:
|
||||||
def __init__(self): pass
|
def __init__(self): pass
|
||||||
def end_paragraph(self, blankline): pass
|
def end_paragraph(self, blankline): pass
|
||||||
def add_line_break(self): pass
|
def add_line_break(self): pass
|
||||||
def add_hor_rule(self): pass
|
def add_hor_rule(self, abswidth=None, percentwidth=1.0,
|
||||||
|
height=None, align=None): pass
|
||||||
def add_label_data(self, format, counter): pass
|
def add_label_data(self, format, counter): pass
|
||||||
def add_flowing_data(self, data): pass
|
def add_flowing_data(self, data): pass
|
||||||
def add_literal_data(self, data): pass
|
def add_literal_data(self, data): pass
|
||||||
def flush_softspace(self): pass
|
def flush_softspace(self): pass
|
||||||
|
def push_alignment(self, align): pass
|
||||||
|
def pop_alignment(self): pass
|
||||||
def push_font(self, x): pass
|
def push_font(self, x): pass
|
||||||
def pop_font(self): pass
|
def pop_font(self): pass
|
||||||
def push_margin(self, margin): pass
|
def push_margin(self, margin): pass
|
||||||
def pop_margin(self): pass
|
def pop_margin(self): pass
|
||||||
def set_spacing(self, spacing): pass
|
def set_spacing(self, spacing): pass
|
||||||
def push_style(self, style): pass
|
def push_style(self, *styles): pass
|
||||||
def pop_style(self): pass
|
def pop_style(self, n=1): pass
|
||||||
|
def assert_line_data(self, flag=1): pass
|
||||||
|
|
||||||
|
|
||||||
class AbstractFormatter:
|
class AbstractFormatter:
|
||||||
|
|
||||||
def __init__(self, writer):
|
def __init__(self, writer):
|
||||||
self.writer = writer # Output device
|
self.writer = writer # Output device
|
||||||
|
self.align = None # Current alignment
|
||||||
|
self.align_stack = [] # Alignment stack
|
||||||
self.font_stack = [] # Font state
|
self.font_stack = [] # Font state
|
||||||
self.margin_stack = [] # Margin state
|
self.margin_stack = [] # Margin state
|
||||||
self.spacing = None # Vertical spacing state
|
self.spacing = None # Vertical spacing state
|
||||||
self.style_stack = [] # Other state, e.g. color
|
self.style_stack = [] # Other state, e.g. color
|
||||||
self.nospace = 1 # Should leading space be suppressed
|
self.nospace = 1 # Should leading space be suppressed
|
||||||
self.softspace = 0 # Should a space be inserted
|
self.softspace = 0 # Should a space be inserted
|
||||||
|
self.para_end = 1 # Just ended a paragraph
|
||||||
|
self.parskip = 0 # Skipped space between paragraphs?
|
||||||
|
self.hard_break = 1 # Have a hard break
|
||||||
|
self.have_label = 0
|
||||||
|
|
||||||
def end_paragraph(self, blankline):
|
def end_paragraph(self, blankline):
|
||||||
if not self.nospace:
|
if not self.hard_break:
|
||||||
self.writer.send_paragraph(blankline)
|
self.writer.send_line_break()
|
||||||
self.nospace = 1
|
self.have_label = 0
|
||||||
|
if self.parskip < blankline and not self.have_label:
|
||||||
|
self.writer.send_paragraph(blankline - self.parskip)
|
||||||
|
self.parskip = blankline
|
||||||
|
self.have_label = 0
|
||||||
|
self.hard_break = self.nospace = self.para_end = 1
|
||||||
self.softspace = 0
|
self.softspace = 0
|
||||||
|
|
||||||
def add_line_break(self):
|
def add_line_break(self):
|
||||||
self.writer.send_line_break()
|
if not (self.hard_break or self.para_end):
|
||||||
self.nospace = 1
|
self.writer.send_line_break()
|
||||||
|
self.have_label = self.parskip = 0
|
||||||
|
self.hard_break = self.nospace = 1
|
||||||
self.softspace = 0
|
self.softspace = 0
|
||||||
|
|
||||||
def add_hor_rule(self):
|
def add_hor_rule(self, *args, **kw):
|
||||||
self.writer.send_hor_rule()
|
if not self.hard_break:
|
||||||
self.nospace = 1
|
self.writer.send_line_break()
|
||||||
self.softspace = 0
|
apply(self.writer.send_hor_rule, args, kw)
|
||||||
|
self.hard_break = self.nospace = 1
|
||||||
|
self.have_label = self.para_end = self.softspace = self.parskip = 0
|
||||||
|
|
||||||
def add_label_data(self, format, counter):
|
def add_label_data(self, format, counter, blankline = None):
|
||||||
data = self.format_counter(format, counter)
|
if self.have_label or not self.hard_break:
|
||||||
self.writer.send_label_data(data)
|
self.writer.send_line_break()
|
||||||
|
if not self.para_end:
|
||||||
|
self.writer.send_paragraph((blankline and 1) or 0)
|
||||||
|
if type(format) is StringType:
|
||||||
|
self.writer.send_label_data(self.format_counter(format, counter))
|
||||||
|
else:
|
||||||
|
self.writer.send_label_data(format)
|
||||||
|
self.nospace = self.have_label = self.hard_break = self.para_end = 1
|
||||||
|
self.softspace = self.parskip = 0
|
||||||
|
|
||||||
def format_counter(self, format, counter):
|
def format_counter(self, format, counter):
|
||||||
if counter <= 0:
|
|
||||||
return format
|
|
||||||
label = ''
|
label = ''
|
||||||
for c in format:
|
for c in format:
|
||||||
try:
|
try:
|
||||||
if c == '1':
|
if c == '1':
|
||||||
c = '%d' % counter
|
label = label + ('%d' % counter)
|
||||||
elif c in 'aA':
|
elif c in 'aA':
|
||||||
c = self.format_letter(c, counter)
|
if counter > 0:
|
||||||
|
label = label + self.format_letter(c, counter)
|
||||||
elif c in 'iI':
|
elif c in 'iI':
|
||||||
c = self.format_roman(c, counter)
|
if counter > 0:
|
||||||
|
label = label + self.format_roman(c, counter)
|
||||||
|
else:
|
||||||
|
label = label + c
|
||||||
except:
|
except:
|
||||||
pass
|
label = label + c
|
||||||
label = label + c
|
|
||||||
return label
|
return label
|
||||||
|
|
||||||
def format_letter(self, case, counter):
|
def format_letter(self, case, counter):
|
||||||
|
@ -85,15 +114,14 @@ class AbstractFormatter:
|
||||||
def format_roman(self, case, counter):
|
def format_roman(self, case, counter):
|
||||||
ones = ['i', 'x', 'c', 'm']
|
ones = ['i', 'x', 'c', 'm']
|
||||||
fives = ['v', 'l', 'd']
|
fives = ['v', 'l', 'd']
|
||||||
label = ''
|
label, index = '', 0
|
||||||
index = 0
|
|
||||||
# This will die of IndexError when counter is too big
|
# This will die of IndexError when counter is too big
|
||||||
while counter > 0:
|
while counter > 0:
|
||||||
counter, x = divmod(counter, 10)
|
counter, x = divmod(counter, 10)
|
||||||
if x == 9:
|
if x == 9:
|
||||||
s = ones[index] + ones[index+1]
|
label = ones[index] + ones[index+1] + label
|
||||||
elif x == 4:
|
elif x == 4:
|
||||||
s = ones[index] + fives[index]
|
label = ones[index] + fives[index] + label
|
||||||
else:
|
else:
|
||||||
if x >= 5:
|
if x >= 5:
|
||||||
s = fives[index]
|
s = fives[index]
|
||||||
|
@ -101,41 +129,73 @@ class AbstractFormatter:
|
||||||
else:
|
else:
|
||||||
s = ''
|
s = ''
|
||||||
s = s + ones[index]*x
|
s = s + ones[index]*x
|
||||||
label = s + label
|
label = s + label
|
||||||
index = index + 1
|
index = index + 1
|
||||||
if case == 'I': label = string.upper(label)
|
if case == 'I':
|
||||||
|
return string.upper(label)
|
||||||
return label
|
return label
|
||||||
|
|
||||||
def add_flowing_data(self, data):
|
def add_flowing_data(self, data,
|
||||||
|
# These are only here to load them into locals:
|
||||||
|
whitespace = string.whitespace,
|
||||||
|
join = string.join, split = string.split):
|
||||||
if not data: return
|
if not data: return
|
||||||
# The following looks a bit convoluted but is a great improvement over
|
# The following looks a bit convoluted but is a great improvement over
|
||||||
# data = regsub.gsub('[' + string.whitespace + ']+', ' ', data)
|
# data = regsub.gsub('[' + string.whitespace + ']+', ' ', data)
|
||||||
prespace = data[0] in string.whitespace
|
prespace = data[:1] in whitespace
|
||||||
postspace = data[-1] in string.whitespace
|
postspace = data[-1:] in whitespace
|
||||||
data = string.join(string.split(data))
|
data = join(split(data))
|
||||||
if self.nospace and prespace:
|
if self.nospace and not data:
|
||||||
if not data: return
|
return
|
||||||
prespace = 0
|
elif prespace or self.softspace:
|
||||||
elif self.softspace:
|
if not data:
|
||||||
prespace = 1
|
if not self.nospace:
|
||||||
self.nospace = self.softspace = 0
|
self.softspace = 1
|
||||||
if postspace:
|
self.parskip = 0
|
||||||
self.softspace = 1
|
return
|
||||||
if prespace: data = ' ' + data
|
if not self.nospace:
|
||||||
|
data = ' ' + data
|
||||||
|
self.hard_break = self.nospace = self.para_end = \
|
||||||
|
self.parskip = self.have_label = 0
|
||||||
|
self.softspace = postspace
|
||||||
self.writer.send_flowing_data(data)
|
self.writer.send_flowing_data(data)
|
||||||
|
|
||||||
def add_literal_data(self, data):
|
def add_literal_data(self, data):
|
||||||
if self.softspace and data[:1] != '\n':
|
if not data: return
|
||||||
data = ' ' + data
|
# Caller is expected to cause flush_softspace() if needed.
|
||||||
self.nospace = self.softspace = 0
|
self.hard_break = data[-1:] == '\n'
|
||||||
|
self.nospace = self.para_end = self.softspace = \
|
||||||
|
self.parskip = self.have_label = 0
|
||||||
self.writer.send_literal_data(data)
|
self.writer.send_literal_data(data)
|
||||||
|
|
||||||
def flush_softspace(self):
|
def flush_softspace(self):
|
||||||
if self.softspace:
|
if self.softspace:
|
||||||
self.nospace = self.softspace = 0
|
self.hard_break = self.nospace = self.para_end = self.parskip = \
|
||||||
|
self.have_label = self.softspace = 0
|
||||||
self.writer.send_flowing_data(' ')
|
self.writer.send_flowing_data(' ')
|
||||||
|
|
||||||
|
def push_alignment(self, align):
|
||||||
|
if align and align != self.align:
|
||||||
|
self.writer.new_alignment(align)
|
||||||
|
self.align = align
|
||||||
|
self.align_stack.append(align)
|
||||||
|
else:
|
||||||
|
self.align_stack.append(self.align)
|
||||||
|
|
||||||
|
def pop_alignment(self):
|
||||||
|
if self.align_stack:
|
||||||
|
del self.align_stack[-1]
|
||||||
|
if self.align_stack:
|
||||||
|
self.align = align = self.align_stack[-1]
|
||||||
|
self.writer.new_alignment(align)
|
||||||
|
else:
|
||||||
|
self.align = None
|
||||||
|
self.writer.new_alignment(None)
|
||||||
|
|
||||||
def push_font(self, (size, i, b, tt)):
|
def push_font(self, (size, i, b, tt)):
|
||||||
|
if self.softspace:
|
||||||
|
self.hard_break = self.nospace = self.para_end = self.softspace = 0
|
||||||
|
self.writer.send_flowing_data(' ')
|
||||||
if self.font_stack:
|
if self.font_stack:
|
||||||
csize, ci, cb, ctt = self.font_stack[-1]
|
csize, ci, cb, ctt = self.font_stack[-1]
|
||||||
if size is AS_IS: size = csize
|
if size is AS_IS: size = csize
|
||||||
|
@ -147,6 +207,9 @@ class AbstractFormatter:
|
||||||
self.writer.new_font(font)
|
self.writer.new_font(font)
|
||||||
|
|
||||||
def pop_font(self):
|
def pop_font(self):
|
||||||
|
if self.softspace:
|
||||||
|
self.hard_break = self.nospace = self.para_end = self.softspace = 0
|
||||||
|
self.writer.send_flowing_data(' ')
|
||||||
if self.font_stack:
|
if self.font_stack:
|
||||||
del self.font_stack[-1]
|
del self.font_stack[-1]
|
||||||
if self.font_stack:
|
if self.font_stack:
|
||||||
|
@ -157,36 +220,69 @@ class AbstractFormatter:
|
||||||
|
|
||||||
def push_margin(self, margin):
|
def push_margin(self, margin):
|
||||||
self.margin_stack.append(margin)
|
self.margin_stack.append(margin)
|
||||||
self.writer.new_margin(margin, len(self.margin_stack))
|
fstack = filter(None, self.margin_stack)
|
||||||
|
if not margin and fstack:
|
||||||
|
margin = fstack[-1]
|
||||||
|
self.writer.new_margin(margin, len(fstack))
|
||||||
|
|
||||||
def pop_margin(self):
|
def pop_margin(self):
|
||||||
if self.margin_stack:
|
if self.margin_stack:
|
||||||
del self.margin_stack[-1]
|
del self.margin_stack[-1]
|
||||||
if self.margin_stack:
|
fstack = filter(None, self.margin_stack)
|
||||||
margin = self.margin_stack[-1]
|
if fstack:
|
||||||
|
margin = fstack[-1]
|
||||||
else:
|
else:
|
||||||
margin = None
|
margin = None
|
||||||
self.writer.new_margin(margin, len(self.margin_stack))
|
self.writer.new_margin(margin, len(fstack))
|
||||||
|
|
||||||
def set_spacing(self, spacing):
|
def set_spacing(self, spacing):
|
||||||
self.spacing = spacing
|
self.spacing = spacing
|
||||||
self.writer.new_spacing(spacing)
|
self.writer.new_spacing(spacing)
|
||||||
|
|
||||||
def push_style(self, style):
|
def push_style(self, *styles):
|
||||||
self.style_stack.append(style)
|
if self.softspace:
|
||||||
|
self.hard_break = self.nospace = self.para_end = self.softspace = 0
|
||||||
|
self.writer.send_flowing_data(' ')
|
||||||
|
for style in styles:
|
||||||
|
self.style_stack.append(style)
|
||||||
self.writer.new_styles(tuple(self.style_stack))
|
self.writer.new_styles(tuple(self.style_stack))
|
||||||
|
|
||||||
def pop_style(self):
|
def pop_style(self, n=1):
|
||||||
if self.style_stack:
|
if self.softspace:
|
||||||
del self.style_stack[-1]
|
self.hard_break = self.nospace = self.para_end = self.softspace = 0
|
||||||
|
self.writer.send_flowing_data(' ')
|
||||||
|
del self.style_stack[-n:]
|
||||||
self.writer.new_styles(tuple(self.style_stack))
|
self.writer.new_styles(tuple(self.style_stack))
|
||||||
|
|
||||||
|
def assert_line_data(self, flag=1):
|
||||||
|
self.nospace = self.hard_break = not flag
|
||||||
|
self.para_end = self.have_label = 0
|
||||||
|
|
||||||
|
|
||||||
|
class NullWriter:
|
||||||
|
"""Minimal writer interface to use in testing.
|
||||||
|
"""
|
||||||
|
def new_alignment(self, align): pass
|
||||||
|
def new_font(self, font): pass
|
||||||
|
def new_margin(self, margin, level): pass
|
||||||
|
def new_spacing(self, spacing): pass
|
||||||
|
def new_styles(self, styles): pass
|
||||||
|
def send_paragraph(self, blankline): pass
|
||||||
|
def send_line_break(self): pass
|
||||||
|
def send_hor_rule(self, *args, **kw): pass
|
||||||
|
def send_label_data(self, data): pass
|
||||||
|
def send_flowing_data(self, data): pass
|
||||||
|
def send_literal_data(self, data): pass
|
||||||
|
|
||||||
|
|
||||||
class AbstractWriter:
|
class AbstractWriter:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def new_alignment(self, align):
|
||||||
|
print "new_alignment(%s)" % `align`
|
||||||
|
|
||||||
def new_font(self, font):
|
def new_font(self, font):
|
||||||
print "new_font(%s)" % `font`
|
print "new_font(%s)" % `font`
|
||||||
|
|
||||||
|
@ -205,7 +301,7 @@ class AbstractWriter:
|
||||||
def send_line_break(self):
|
def send_line_break(self):
|
||||||
print "send_line_break()"
|
print "send_line_break()"
|
||||||
|
|
||||||
def send_hor_rule(self):
|
def send_hor_rule(self, *args, **kw):
|
||||||
print "send_hor_rule()"
|
print "send_hor_rule()"
|
||||||
|
|
||||||
def send_label_data(self, data):
|
def send_label_data(self, data):
|
||||||
|
@ -240,7 +336,7 @@ class DumbWriter(AbstractWriter):
|
||||||
self.col = 0
|
self.col = 0
|
||||||
self.atbreak = 0
|
self.atbreak = 0
|
||||||
|
|
||||||
def send_hor_rule(self):
|
def send_hor_rule(self, *args, **kw):
|
||||||
self.file.write('\n')
|
self.file.write('\n')
|
||||||
self.file.write('-'*self.maxcol)
|
self.file.write('-'*self.maxcol)
|
||||||
self.file.write('\n')
|
self.file.write('\n')
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue