既存の[[クレート]]を調査してみたが、いずれもライブラリ利用として対応しているものはなさそう。[[Similar]]を使って表示をカスタマイズしてみる。 ## 実装 幅が違う問題は等幅フォントが利用される前提で、[[ASCII]]を1スペース、日本語を2スペースで数えることにしている。 ```rust use similar::{ChangeTag, TextDiff}; use unicode_width::UnicodeWidthStr; fn create_side_by_side_diff(text1: &str, text2: &str, max_width: usize) -> String { TextDiff::from_lines(text1, text2) .iter_all_changes() .map(|change| { let content = change.to_string().trim_end_matches('\n').to_string(); let width = max_width - (content.width() - content.chars().count()); match change.tag() { ChangeTag::Delete => format!( "{:>6} | {:<width$} | {:>6} | {:<blank_width$} |", change.old_index().unwrap() + 1, content, "", "", blank_width = max_width, width = width, ), ChangeTag::Insert => format!( "{:>6} | {:<blank_width$} | {:>6} | {:<width$} |", "", "", change.new_index().unwrap() + 1, content, blank_width = max_width, width = width ), ChangeTag::Equal => format!( "{:>6} | {token:<width$} | {:>6} | {token:<width$} |", change.old_index().unwrap() + 1, change.new_index().unwrap() + 1, token = content, width = width ), } }) .collect::<Vec<_>>() .join("\n") } ``` ## テスト ```txt あああ bbb ccc ddd いいいいいーeee かかお FFFFFFFFFF ggg ``` と ```txt あああ bbb いいいいいーeee かかか ffffffffff ggg ``` を比較してみる。以下のように呼び出す。 ```rust fn main() { let diff_text = create_side_by_side_diff( " あああ bbb ccc ddd いいいいいーeee かかお FFFFFFFFFF ggg" .trim(), " あああ bbb いいいいいーeee かかか ffffffffff ggg" .trim(), 20, ); println!("{diff_text}"); } ``` 結果は以下のようになる。 ```txt 1 | あああ | 1 | あああ | 2 | bbb | 2 | bbb | 3 | ccc | | | 4 | ddd | | | 5 | いいいいいーeee | 3 | いいいいいーeee | 6 | かかお | | | 7 | FFFFFFFFFF | | | | | 4 | かかか | | | 5 | ffffffffff | 8 | ggg | 6 | ggg | ``` となる。 [[Minerva]]は等幅フォントを利用していないので、上記の結果は若干ずれて見えるかもしれないが、等幅フォントだと以下画像のように表示される。 ![[Pasted image 20230115172450.png]]