~bzr-pqm/bzr/bzr.dev

« back to all changes in this revision

Viewing changes to bzrlib/rio.py

Merge from bzr.dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
315
315
        return stanza
316
316
    else:     # didn't see any content
317
317
        return None    
 
318
 
 
319
 
 
320
def to_patch_lines(stanza, max_width=72):
 
321
    """Convert a stanza into RIO-Patch format lines.
 
322
 
 
323
    RIO-Patch is a RIO variant designed to be e-mailed as part of a patch.
 
324
    It resists common forms of damage such as newline conversion or the removal
 
325
    of trailing whitespace, yet is also reasonably easy to read.
 
326
 
 
327
    :param max_width: The maximum number of characters per physical line.
 
328
    :return: a list of lines
 
329
    """
 
330
    assert max_width > 6
 
331
    max_rio_width = max_width - 4
 
332
    lines = []
 
333
    for pline in stanza.to_lines():
 
334
        for line in pline.split('\n')[:-1]:
 
335
            line = re.sub('\\\\', '\\\\\\\\', line)
 
336
            while len(line) > 0:
 
337
                partline = line[:max_rio_width]
 
338
                line = line[max_rio_width:]
 
339
                if len(line) > 0 and line[0] != [' ']:
 
340
                    break_index = -1
 
341
                    break_index = partline.rfind(' ', -20)
 
342
                    if break_index < 3:
 
343
                        break_index = partline.rfind('-', -20)
 
344
                        break_index += 1
 
345
                    if break_index < 3:
 
346
                        break_index = partline.rfind('/', -20)
 
347
                    if break_index >= 3:
 
348
                        line = partline[break_index:] + line
 
349
                        partline = partline[:break_index]
 
350
                if len(line) > 0:
 
351
                    line = '  ' + line
 
352
                partline = re.sub('\r', '\\\\r', partline)
 
353
                blank_line = False
 
354
                if len(line) > 0:
 
355
                    partline += '\\'
 
356
                elif re.search(' $', partline):
 
357
                    partline += '\\'
 
358
                    blank_line = True
 
359
                lines.append('# ' + partline + '\n')
 
360
                if blank_line:
 
361
                    lines.append('#   \n')
 
362
    return lines
 
363
 
 
364
 
 
365
def _patch_stanza_iter(line_iter):
 
366
    map = {'\\\\': '\\',
 
367
           '\\r' : '\r',
 
368
           '\\\n': ''}
 
369
    def mapget(match):
 
370
        return map[match.group(0)]
 
371
 
 
372
    last_line = None
 
373
    for line in line_iter:
 
374
        if line.startswith('# '):
 
375
            line = line[2:]
 
376
        else:
 
377
            assert line.startswith('#')
 
378
            line = line[1:]
 
379
        if last_line is not None and len(line) > 2:
 
380
            line = line[2:]
 
381
        line = re.sub('\r', '', line)
 
382
        line = re.sub('\\\\(.|\n)', mapget, line)
 
383
        if last_line is None:
 
384
            last_line = line
 
385
        else:
 
386
            last_line += line
 
387
        if last_line[-1] == '\n':
 
388
            yield last_line
 
389
            last_line = None
 
390
    if last_line is not None:
 
391
        yield last_line
 
392
 
 
393
 
 
394
def read_patch_stanza(line_iter):
 
395
    """Convert an iterable of RIO-Patch format lines into a Stanza.
 
396
 
 
397
    RIO-Patch is a RIO variant designed to be e-mailed as part of a patch.
 
398
    It resists common forms of damage such as newline conversion or the removal
 
399
    of trailing whitespace, yet is also reasonably easy to read.
 
400
 
 
401
    :return: a Stanza
 
402
    """
 
403
    return read_stanza(_patch_stanza_iter(line_iter))