mirror of
https://github.com/Mikaela/Limnoria.git
synced 2025-02-16 21:50:41 +01:00
Fix text wrapping when colors cross message boundaries.
This commit is contained in:
parent
b2f2b01dd6
commit
93b0476751
@ -535,10 +535,21 @@ class FormatContext(object):
|
|||||||
s += '\x0f'
|
s += '\x0f'
|
||||||
return s
|
return s
|
||||||
|
|
||||||
|
def size(self):
|
||||||
|
"""Returns the number of bytes needed to reproduce this context in an
|
||||||
|
IRC string."""
|
||||||
|
prefix_size = self.bold + self.reverse + self.underline + \
|
||||||
|
bool(self.fg) + bool(self.bg)
|
||||||
|
if prefix_size:
|
||||||
|
return prefix_size + 1 # '\x0f'
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
class FormatParser(object):
|
class FormatParser(object):
|
||||||
def __init__(self, s):
|
def __init__(self, s):
|
||||||
self.fd = minisix.io.StringIO(s)
|
self.fd = minisix.io.StringIO(s)
|
||||||
self.last = None
|
self.last = None
|
||||||
|
self.max_context_size = 0
|
||||||
|
|
||||||
def getChar(self):
|
def getChar(self):
|
||||||
if self.last is not None:
|
if self.last is not None:
|
||||||
@ -557,14 +568,22 @@ class FormatParser(object):
|
|||||||
while c:
|
while c:
|
||||||
if c == '\x02':
|
if c == '\x02':
|
||||||
context.bold = not context.bold
|
context.bold = not context.bold
|
||||||
|
self.max_context_size = max(
|
||||||
|
self.max_context_size, context.size())
|
||||||
elif c == '\x16':
|
elif c == '\x16':
|
||||||
context.reverse = not context.reverse
|
context.reverse = not context.reverse
|
||||||
|
self.max_context_size = max(
|
||||||
|
self.max_context_size, context.size())
|
||||||
elif c == '\x1f':
|
elif c == '\x1f':
|
||||||
context.underline = not context.underline
|
context.underline = not context.underline
|
||||||
|
self.max_context_size = max(
|
||||||
|
self.max_context_size, context.size())
|
||||||
elif c == '\x0f':
|
elif c == '\x0f':
|
||||||
context.reset()
|
context.reset()
|
||||||
elif c == '\x03':
|
elif c == '\x03':
|
||||||
self.getColor(context)
|
self.getColor(context)
|
||||||
|
self.max_context_size = max(
|
||||||
|
self.max_context_size, context.size())
|
||||||
c = self.getChar()
|
c = self.getChar()
|
||||||
return context
|
return context
|
||||||
|
|
||||||
@ -597,8 +616,17 @@ class FormatParser(object):
|
|||||||
self.ungetChar(c)
|
self.ungetChar(c)
|
||||||
|
|
||||||
def wrap(s, length, break_on_hyphens = False):
|
def wrap(s, length, break_on_hyphens = False):
|
||||||
|
# Get the maximum number of bytes needed to format a chunk of the string
|
||||||
|
# at any point.
|
||||||
|
# This is an overapproximation of what each chunk will need, but it's
|
||||||
|
# either that or make the code of byteTextWrap aware of contexts, and its
|
||||||
|
# code is complicated enough as it is already.
|
||||||
|
parser = FormatParser(s)
|
||||||
|
parser.parse()
|
||||||
|
format_overhead = parser.max_context_size
|
||||||
|
|
||||||
processed = []
|
processed = []
|
||||||
chunks = utils.str.byteTextWrap(s, length)
|
chunks = utils.str.byteTextWrap(s, length - format_overhead)
|
||||||
context = None
|
context = None
|
||||||
for chunk in chunks:
|
for chunk in chunks:
|
||||||
if context is not None:
|
if context is not None:
|
||||||
|
@ -227,6 +227,11 @@ class FunctionsTestCase(SupyTestCase):
|
|||||||
r = ircutils.wrap(s, 139)
|
r = ircutils.wrap(s, 139)
|
||||||
self.assertTrue(max(map(pred, r)) <= 139)
|
self.assertTrue(max(map(pred, r)) <= 139)
|
||||||
|
|
||||||
|
s = '\x02\x16 barbazqux' + ('foobarbazqux ' * 20)[0:-1]
|
||||||
|
r = ircutils.wrap(s, 91)
|
||||||
|
print(list(map(pred, r)))
|
||||||
|
self.assertTrue(max(map(pred, r)) <= 91)
|
||||||
|
|
||||||
|
|
||||||
def testSafeArgument(self):
|
def testSafeArgument(self):
|
||||||
s = 'I have been running for 9 seconds'
|
s = 'I have been running for 9 seconds'
|
||||||
|
Loading…
x
Reference in New Issue
Block a user