c2rust-refactor 0.15.0

C2Rust refactoring tool implementation
'''Run `rustfmt` on before-and-after file contents, to produce nicer looking
diffs.'''
import difflib
import os
import tempfile
from typing import List

from plumbum.cmd import rustfmt

from literate.annot import Span
from literate.file import File

def format_text_in_file(text: str, path: str) -> str:
    '''Run `rustfmt` on `text`, using `path` as a temporary file.  Returns the
    formatted text.'''
    with open(path, 'w') as f:
        f.write(text)

    rustfmt['--unstable-features', '--skip-children', path]()

    with open(path, 'r') as f:
        return f.read()

def format_files(all_files: List[File]):
    '''Format the `unformatted` text of every file in `all_files`, and set the
    formatted text for each one.'''
    with tempfile.TemporaryDirectory() as td:
        path = os.path.join(td, 'fmt.rs')

        fmt_text = {}
        for i, f in enumerate(all_files):
            print('formatting file %d (%s)' % (i, f.path))
            f.set_formatted(format_text_in_file(f.unformatted, path))


def init_fmt_map(f: File):
    '''Initialize a `File`'s `fmt_map` field, which describes the mapping from
    unformatted text positions to formatted ones.'''
    matching_spans = []
    sm = difflib.SequenceMatcher(a=f.unformatted, b=f.text)
    for tag, i1, i2, j1, j2 in sm.get_opcodes():
        if tag == 'equal':
            matching_spans.append((Span(i1, i2), j1))

    fmt_map_index = [s.start for s, pos in matching_spans]

    f.set_fmt_map(matching_spans, fmt_map_index)