def _replace_lines_from_to(old_lines, new_lines, start_pos, end_pos):
    print('replace lines from line', start_pos, 'to line', end_pos)
    old_indent = get_indent(old_lines[start_pos])
    new_indent = get_indent(new_lines[0])
    if new_indent:
        missing_indent = old_indent[:-len(new_indent)]
    else:
        missing_indent = old_indent
    indented_new_lines = [missing_indent + l for l in new_lines]
    return '\n'.join(old_lines[:start_pos] + indented_new_lines +
                     old_lines[end_pos + 1:])
def _replace_lines_from_to(old_lines, new_lines, start_pos, end_pos):
    print('replace lines from line', start_pos, 'to line', end_pos)
    old_indent = get_indent(old_lines[start_pos])
    new_indent = get_indent(new_lines[0])
    if new_indent:
        missing_indent = old_indent[:-len(new_indent)]
    else:
        missing_indent = old_indent
    indented_new_lines = [missing_indent + l for l in new_lines]
    return '\n'.join(
        old_lines[:start_pos] +
        indented_new_lines +
        old_lines[end_pos + 1:]
    )
def _replace_single_line(old_lines, new_lines):
    print('replace single line')
    new_line = new_lines[0]
    line_finder = lambda l: number_of_identical_chars(l, new_line)
    likely_line = sorted(old_lines, key=line_finder)[-1]
    new_line = get_indent(likely_line) + new_line
    new_content = '\n'.join(old_lines).replace(likely_line, new_line)
    return new_content
def _replace_single_line(old_lines, new_lines):
    print('replace single line')
    new_line = new_lines[0]
    line_finder = lambda l: number_of_identical_chars(l, new_line)
    likely_line = sorted(old_lines, key=line_finder)[-1]
    new_line = get_indent(likely_line) + new_line
    new_content = '\n'.join(old_lines).replace(likely_line, new_line)
    return new_content
def _replace_lines_from(old_lines, new_lines, start_pos):
    print('replace lines from line', start_pos)
    start_line_in_old = old_lines[start_pos]
    indent = get_indent(start_line_in_old)
    for ix, new_line in enumerate(new_lines):
        if len(old_lines) > start_pos + ix:
            old_lines[start_pos + ix] = indent + new_line
        else:
            old_lines.append(indent + new_line)
    return '\n'.join(old_lines)
def _replace_lines_from(old_lines, new_lines, start_pos):
    print('replace lines from line', start_pos)
    start_line_in_old = old_lines[start_pos]
    indent = get_indent(start_line_in_old)
    for ix, new_line in enumerate(new_lines):
        if len(old_lines) > start_pos + ix:
            old_lines[start_pos + ix] = indent + new_line
        else:
            old_lines.append(indent + new_line)
    return '\n'.join(old_lines)
def _write_to_file(path, new_contents):
    source = Source.from_path(path)
    # strip callouts
    new_contents = re.sub(r' +#$', '', new_contents, flags=re.MULTILINE)
    new_contents = re.sub(r' +//$', '', new_contents, flags=re.MULTILINE)

    if not os.path.exists(path):
        dir = os.path.dirname(path)
        if not os.path.exists(dir):
            os.makedirs(dir)

    else:
        old_lines = source.lines
        new_lines = new_contents.strip('\n').split('\n')

        if "[..." not in new_contents:
            new_contents = _replace_lines_in(old_lines, new_lines)

        else:
            if new_contents.count("[...") == 1:
                split_line = [l for l in new_lines if "[..." in l][0]
                split_line_pos = new_lines.index(split_line)

                if split_line_pos == 0:
                    new_contents = _replace_lines_in(old_lines, new_lines[1:])

                elif split_line == new_lines[-1]:
                    new_contents = _replace_lines_in(old_lines, new_lines[:-1])

                elif split_line_pos == 1:
                    if 'import' in new_lines[0]:
                        new_contents = add_import_and_new_lines(
                            new_lines, old_lines)
                    elif 'class' in new_lines[0]:
                        new_contents = add_to_class(new_lines, old_lines)

                else:
                    lines_before = new_lines[:split_line_pos]
                    last_line_before = lines_before[-1]
                    lines_after = new_lines[split_line_pos + 1:]

                    last_old_line = [
                        l for l in old_lines
                        if l.strip() == last_line_before.strip()
                    ][0]
                    last_old_line_pos = old_lines.index(last_old_line)
                    old_lines_after = old_lines[last_old_line_pos + 1:]

                    # special-case: stray browser.quit in chap. 2
                    if 'rest of comments' in split_line:
                        assert 'browser.quit()' in [
                            l.strip() for l in old_lines_after
                        ]
                        assert old_lines_after[-2] == 'browser.quit()'
                        old_lines_after = old_lines_after[:-2]

                    new_contents = '\n'.join(
                        lines_before +
                        [get_indent(split_line) + l
                         for l in old_lines_after] + lines_after)

            elif new_contents.strip().startswith(
                    "[...]") and new_contents.endswith("[...]"):
                new_contents = _replace_lines_in(old_lines, new_lines[1:-1])
            else:
                raise Exception("I don't know how to deal with this")

    # strip trailing whitespace
    new_contents = re.sub(r'^ +$', '', new_contents, flags=re.MULTILINE)
    source.update(new_contents)
    source.write()
def _write_to_file(path, new_contents):
    source = Source.from_path(path)
    # strip callouts
    new_contents = re.sub(r' +#$', '', new_contents, flags=re.MULTILINE)
    new_contents = re.sub(r' +//$', '', new_contents, flags=re.MULTILINE)

    if not os.path.exists(path):
        dir = os.path.dirname(path)
        if not os.path.exists(dir):
            os.makedirs(dir)

    else:
        old_lines = source.lines
        new_lines = new_contents.strip('\n').split('\n')

        if "[..." not in new_contents:
            new_contents = _replace_lines_in(old_lines, new_lines)

        else:
            if new_contents.count("[...") == 1:
                split_line = [l for l in new_lines if "[..." in l][0]
                split_line_pos = new_lines.index(split_line)

                if split_line_pos == 0:
                    new_contents = _replace_lines_in(old_lines, new_lines[1:])

                elif split_line == new_lines[-1]:
                    new_contents = _replace_lines_in(old_lines, new_lines[:-1])

                elif split_line_pos == 1:
                    if 'import' in new_lines[0]:
                        new_contents = add_import_and_new_lines(new_lines, old_lines)
                    elif 'class' in new_lines[0]:
                        new_contents = add_to_class(new_lines, old_lines)

                else:
                    lines_before = new_lines[:split_line_pos]
                    last_line_before = lines_before[-1]
                    lines_after = new_lines[split_line_pos + 1:]

                    last_old_line = [
                        l for l in old_lines if l.strip() == last_line_before.strip()
                    ][0]
                    last_old_line_pos = old_lines.index(last_old_line)
                    old_lines_after = old_lines[last_old_line_pos + 1:]

                    # special-case: stray browser.quit in chap. 2
                    if 'rest of comments' in split_line:
                        assert 'browser.quit()' in [l.strip() for l in old_lines_after]
                        assert old_lines_after[-2] == 'browser.quit()'
                        old_lines_after = old_lines_after[:-2]

                    new_contents = '\n'.join(
                        lines_before +
                        [get_indent(split_line) + l for l in old_lines_after] +
                        lines_after
                    )

            elif new_contents.strip().startswith("[...]") and new_contents.endswith("[...]"):
                new_contents = _replace_lines_in(old_lines, new_lines[1:-1])
            else:
                raise Exception("I don't know how to deal with this")

    # strip trailing whitespace
    new_contents = re.sub(r'^ +$', '', new_contents, flags=re.MULTILINE)
    source.update(new_contents)
    source.write()