pub fn change_positions(lhs_src: &str, rhs_src: &str) -> Vec<MatchedPos> {
    // TODO: If either side is "", don't split each line by words
    // pointlessly. This is common for file additions/removals.
    let lhs_nlp = NewlinePositions::from(lhs_src);
    let rhs_nlp = NewlinePositions::from(rhs_src);

    let mut lhs_offset = 0;
    let mut rhs_offset = 0;

    let mut res = vec![];
    for (kind, lhs_lines, rhs_lines) in changed_parts(lhs_src, rhs_src) {
        match kind {
            TextChangeKind::Unchanged => {
                for (lhs_line, rhs_line) in lhs_lines.iter().zip(rhs_lines) {
                    let lhs_pos = lhs_nlp.from_offsets(lhs_offset, lhs_offset + lhs_line.len() - 1);
                    let rhs_pos = rhs_nlp.from_offsets(rhs_offset, rhs_offset + rhs_line.len() - 1);

                    res.push(MatchedPos {
                        kind: MatchKind::UnchangedToken {
                            highlight: TokenKind::Atom(AtomKind::Normal),
                            self_pos: lhs_pos.clone(),
                            opposite_pos: rhs_pos,
                        },
                        pos: lhs_pos[0],
                    });

                    lhs_offset += lhs_line.len();
                    rhs_offset += rhs_line.len();
                }
            }
            TextChangeKind::Novel => {
                let lhs_part = lhs_lines.join("");
                let rhs_part = rhs_lines.join("");

                for diff_res in myers_diff::slice(&split_words(&lhs_part), &split_words(&rhs_part))
                {
                    match diff_res {
                        myers_diff::DiffResult::Left(lhs_word) => {
                            if *lhs_word != "\n" {
                                let lhs_pos =
                                    lhs_nlp.from_offsets(lhs_offset, lhs_offset + lhs_word.len());
                                res.push(MatchedPos {
                                    kind: MatchKind::NovelWord {
                                        highlight: TokenKind::Atom(AtomKind::Normal),
                                    },
                                    pos: lhs_pos[0],
                                });
                            }

                            lhs_offset += lhs_word.len();
                        }
                        myers_diff::DiffResult::Both(lhs_word, rhs_word) => {
                            if *lhs_word != "\n" {
                                let lhs_pos =
                                    lhs_nlp.from_offsets(lhs_offset, lhs_offset + lhs_word.len());
                                let rhs_pos =
                                    rhs_nlp.from_offsets(rhs_offset, rhs_offset + rhs_word.len());

                                res.push(MatchedPos {
                                    kind: MatchKind::NovelLinePart {
                                        highlight: TokenKind::Atom(AtomKind::Normal),
                                        self_pos: lhs_pos[0],
                                        opposite_pos: rhs_pos,
                                    },
                                    pos: lhs_pos[0],
                                });
                            }

                            lhs_offset += lhs_word.len();
                            rhs_offset += rhs_word.len();
                        }
                        myers_diff::DiffResult::Right(rhs_word) => {
                            rhs_offset += rhs_word.len();
                        }
                    }
                }
            }
        }
    }

    res
}
// TODO: Prefer src/opposite_src nomenclature as this function is called from both sides.
Prefer src/opposite_src nomenclature as this function is called from both sides.
Prefer src / opposite_src nomenclature as this function is called from both sides .
pub fn change_positions(lhs_src: &str, rhs_src: &str) -> Vec<MatchedPos> {
    // TODO: If either side is "", don't split each line by words
    // pointlessly. This is common for file additions/removals.
    let lhs_nlp = NewlinePositions::from(lhs_src);
    let rhs_nlp = NewlinePositions::from(rhs_src);
    let mut lhs_offset = 0;
    let mut rhs_offset = 0;
    let mut res = vec![];
    for (kind, lhs_lines, rhs_lines) in changed_parts(lhs_src, rhs_src) {
        match kind {
            TextChangeKind::Unchanged => {
                for (lhs_line, rhs_line) in lhs_lines.iter().zip(rhs_lines) {
                    let lhs_pos = lhs_nlp.from_offsets(lhs_offset, lhs_offset + lhs_line.len() - 1);
                    let rhs_pos = rhs_nlp.from_offsets(rhs_offset, rhs_offset + rhs_line.len() - 1);
                    res.push(MatchedPos {
                        kind: MatchKind::UnchangedToken {
                            highlight: TokenKind::Atom(AtomKind::Normal),
                            self_pos: lhs_pos.clone(),
                            opposite_pos: rhs_pos,
                        },
                        pos: lhs_pos[0],
                    });
                    lhs_offset += lhs_line.len();
                    rhs_offset += rhs_line.len();
                }
            }
            TextChangeKind::Novel => {
                let lhs_part = lhs_lines.join("");
                let rhs_part = rhs_lines.join("");
                for diff_res in myers_diff::slice(&split_words(&lhs_part), &split_words(&rhs_part))
                {
                    match diff_res {
                        myers_diff::DiffResult::Left(lhs_word) => {
                            if *lhs_word != "\n" {
                                let lhs_pos =
                                    lhs_nlp.from_offsets(lhs_offset, lhs_offset + lhs_word.len());
                                res.push(MatchedPos {
                                    kind: MatchKind::NovelWord {
                                        highlight: TokenKind::Atom(AtomKind::Normal),
                                    },
                                    pos: lhs_pos[0],
                                });
                            }
                            lhs_offset += lhs_word.len();
                        }
                        myers_diff::DiffResult::Both(lhs_word, rhs_word) => {
                            if *lhs_word != "\n" {
                                let lhs_pos =
                                    lhs_nlp.from_offsets(lhs_offset, lhs_offset + lhs_word.len());
                                let rhs_pos =
                                    rhs_nlp.from_offsets(rhs_offset, rhs_offset + rhs_word.len());
                                res.push(MatchedPos {
                                    kind: MatchKind::NovelLinePart {
                                        highlight: TokenKind::Atom(AtomKind::Normal),
                                        self_pos: lhs_pos[0],
                                        opposite_pos: rhs_pos,
                                    },
                                    pos: lhs_pos[0],
                                });
                            }
                            lhs_offset += lhs_word.len();
                            rhs_offset += rhs_word.len();
                        }
                        myers_diff::DiffResult::Right(rhs_word) => {
                            rhs_offset += rhs_word.len();
                        }
                    }
                }
            }
        }
    }
    res
}
pub fn change_positions ( lhs_src : & str , rhs_src : & str ) -> Vec < MatchedPos > { // TODO: If either side is "", don't split each line by words // pointlessly. This is common for file additions/removals. let lhs_nlp = NewlinePositions :: from ( lhs_src ) ; let rhs_nlp = NewlinePositions :: from ( rhs_src ) ; let mut lhs_offset = 0 ; let mut rhs_offset = 0 ; let mut res = vec ! [ ] ; for ( kind , lhs_lines , rhs_lines ) in changed_parts ( lhs_src , rhs_src ) { match kind { TextChangeKind :: Unchanged => { for ( lhs_line , rhs_line ) in lhs_lines . iter ( ) . zip ( rhs_lines ) { let lhs_pos = lhs_nlp . from_offsets ( lhs_offset , lhs_offset + lhs_line . len ( ) - 1 ) ; let rhs_pos = rhs_nlp . from_offsets ( rhs_offset , rhs_offset + rhs_line . len ( ) - 1 ) ; res . push ( MatchedPos { kind : MatchKind :: UnchangedToken { highlight : TokenKind :: Atom ( AtomKind :: Normal ) , self_pos : lhs_pos . clone ( ) , opposite_pos : rhs_pos , } , pos : lhs_pos [ 0 ] , } ) ; lhs_offset += lhs_line . len ( ) ; rhs_offset += rhs_line . len ( ) ; } } TextChangeKind :: Novel => { let lhs_part = lhs_lines . join ( " " ) ; let rhs_part = rhs_lines . join ( " " ) ; for diff_res in myers_diff :: slice ( & split_words ( & lhs_part ) , & split_words ( & rhs_part ) ) { match diff_res { myers_diff :: DiffResult :: Left ( lhs_word ) => { if * lhs_word != " \n " { let lhs_pos = lhs_nlp . from_offsets ( lhs_offset , lhs_offset + lhs_word . len ( ) ) ; res . push ( MatchedPos { kind : MatchKind :: NovelWord { highlight : TokenKind :: Atom ( AtomKind :: Normal ) , } , pos : lhs_pos [ 0 ] , } ) ; } lhs_offset += lhs_word . len ( ) ; } myers_diff :: DiffResult :: Both ( lhs_word , rhs_word ) => { if * lhs_word != " \n " { let lhs_pos = lhs_nlp . from_offsets ( lhs_offset , lhs_offset + lhs_word . len ( ) ) ; let rhs_pos = rhs_nlp . from_offsets ( rhs_offset , rhs_offset + rhs_word . len ( ) ) ; res . push ( MatchedPos { kind : MatchKind :: NovelLinePart { highlight : TokenKind :: Atom ( AtomKind :: Normal ) , self_pos : lhs_pos [ 0 ] , opposite_pos : rhs_pos , } , pos : lhs_pos [ 0 ] , } ) ; } lhs_offset += lhs_word . len ( ) ; rhs_offset += rhs_word . len ( ) ; } myers_diff :: DiffResult :: Right ( rhs_word ) => { rhs_offset += rhs_word . len ( ) ; } } } } } } res }
TODO: Prefer src/opposite_src nomenclature as this function is called from both sides.
TODO : Prefer src / opposite_src nomenclature as this function is called from both sides .
lhs_src
&str
rhs_src
&str