summaryrefslogtreecommitdiffstats
path: root/vendor/dissimilar
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/dissimilar')
-rw-r--r--vendor/dissimilar/.cargo-checksum.json2
-rw-r--r--vendor/dissimilar/Cargo.toml10
-rw-r--r--vendor/dissimilar/LICENSE-APACHE25
-rw-r--r--vendor/dissimilar/README.md6
-rw-r--r--vendor/dissimilar/src/find.rs14
-rw-r--r--vendor/dissimilar/src/lib.rs169
-rw-r--r--vendor/dissimilar/src/range.rs49
-rw-r--r--vendor/dissimilar/src/tests.rs131
-rw-r--r--vendor/dissimilar/tests/test.rs16
9 files changed, 211 insertions, 211 deletions
diff --git a/vendor/dissimilar/.cargo-checksum.json b/vendor/dissimilar/.cargo-checksum.json
index 889c53a44..cfb8c46ea 100644
--- a/vendor/dissimilar/.cargo-checksum.json
+++ b/vendor/dissimilar/.cargo-checksum.json
@@ -1 +1 @@
-{"files":{"Cargo.toml":"abe95bc027ce5fe4aae082e8560c12d43f015ea85453be0ca6df6ded8f29e4da","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"a9480cd29fe4eefae782c5ec20a05f88ca28d3ca1573a893fa423b931e3ca392","benches/bench.rs":"e62b50ebe922590a7251197b50047a3924be98c6193e1f0fbca552d66fd05f9d","benches/document1.txt":"92a6f5c3992d98632eea7a6c6261cf1a26ae484b34358778b774a2d58fd356d3","benches/document2.txt":"8d106ddba8bd4a85a8bb4b59e481b88f536de98046dc8e4f76f7551c265c5dd3","src/find.rs":"32f68fa18bd547f5c716895bc580c12d6fe8503f86044fc0334f1b1e3cd3ac97","src/lib.rs":"7c1bf347cb87d22dde987da421931644dea3ed84e5e48b8dad44cb5579cb9f04","src/range.rs":"8652a374da1f7959ed912891e610a1e72026ba5315362cfb529bd2724ce69fc6","src/tests.rs":"e2a68e2b724ec65a062b634b86114e3a2e445c4693e312c08d9648f6621ea9d2","tests/test.rs":"4dcc2007359d6bf6a48590fcdab9cc81787a18aac8dc9c1c4be1019d95ca690e"},"package":"8c97b9233581d84b8e1e689cdd3a47b6f69770084fc246e86a7f78b0d9c1d4a5"} \ No newline at end of file
+{"files":{"Cargo.toml":"b5579f3eb0d811d6ad116c247138911fee4404c80f49bb6020df06394d0467ec","LICENSE-APACHE":"62c7a1e35f56406896d7aa7ca52d0cc0d272ac022b5d2796e7d6905db8a3636a","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"e081b60ac4ad261ee3c57f32131634017044193b94ce2ebd64d134d22185e79a","benches/bench.rs":"e62b50ebe922590a7251197b50047a3924be98c6193e1f0fbca552d66fd05f9d","benches/document1.txt":"92a6f5c3992d98632eea7a6c6261cf1a26ae484b34358778b774a2d58fd356d3","benches/document2.txt":"8d106ddba8bd4a85a8bb4b59e481b88f536de98046dc8e4f76f7551c265c5dd3","src/find.rs":"4587b9fc3fc32149898c6daf50624c41ab9de9ec4de5baa3a4d3644436dccf5f","src/lib.rs":"9749cf7915c3f5682144f3eb0ec3d1b5d9c3457b740a7ced8e91211be6a8549c","src/range.rs":"9b4f5f0125d927f985cf5c3a92452e4c28273842d9ff7debc2d3584db5d7d0f6","src/tests.rs":"222464295b0558fe505f9d2d53f315dd164cc85e323e32e523f738eec771cdbe","tests/test.rs":"2a4ccfea35304fa2fc2b2b38efe9da6a1b5fd5f6c1247ba01e85232d19b70206"},"package":"210ec60ae7d710bed8683e333e9d2855a8a56a3e9892b38bad3bb0d4d29b0d5e"} \ No newline at end of file
diff --git a/vendor/dissimilar/Cargo.toml b/vendor/dissimilar/Cargo.toml
index d657b1742..3fdb995a5 100644
--- a/vendor/dissimilar/Cargo.toml
+++ b/vendor/dissimilar/Cargo.toml
@@ -11,9 +11,9 @@
[package]
edition = "2018"
-rust-version = "1.31"
+rust-version = "1.36"
name = "dissimilar"
-version = "1.0.4"
+version = "1.0.6"
authors = ["David Tolnay <dtolnay@gmail.com>"]
description = "Diff library with semantic cleanup, based on Google's diff-match-patch"
documentation = "https://docs.rs/dissimilar"
@@ -28,3 +28,9 @@ repository = "https://github.com/dtolnay/dissimilar"
[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]
+
+[lib]
+doc-scrape-examples = false
+
+[dev-dependencies.once_cell]
+version = "1"
diff --git a/vendor/dissimilar/LICENSE-APACHE b/vendor/dissimilar/LICENSE-APACHE
index 16fe87b06..1b5ec8b78 100644
--- a/vendor/dissimilar/LICENSE-APACHE
+++ b/vendor/dissimilar/LICENSE-APACHE
@@ -174,28 +174,3 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
-
-APPENDIX: How to apply the Apache License to your work.
-
- To apply the Apache License to your work, attach the following
- boilerplate notice, with the fields enclosed by brackets "[]"
- replaced with your own identifying information. (Don't include
- the brackets!) The text should be enclosed in the appropriate
- comment syntax for the file format. We also recommend that a
- file or class name and description of purpose be included on the
- same "printed page" as the copyright notice for easier
- identification within third-party archives.
-
-Copyright [yyyy] [name of copyright owner]
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
diff --git a/vendor/dissimilar/README.md b/vendor/dissimilar/README.md
index 492bced22..82ce66995 100644
--- a/vendor/dissimilar/README.md
+++ b/vendor/dissimilar/README.md
@@ -3,8 +3,8 @@ Dissimilar: diff library with semantic cleanup
[<img alt="github" src="https://img.shields.io/badge/github-dtolnay/dissimilar-8da0cb?style=for-the-badge&labelColor=555555&logo=github" height="20">](https://github.com/dtolnay/dissimilar)
[<img alt="crates.io" src="https://img.shields.io/crates/v/dissimilar.svg?style=for-the-badge&color=fc8d62&logo=rust" height="20">](https://crates.io/crates/dissimilar)
-[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-dissimilar-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K" height="20">](https://docs.rs/dissimilar)
-[<img alt="build status" src="https://img.shields.io/github/workflow/status/dtolnay/dissimilar/CI/master?style=for-the-badge" height="20">](https://github.com/dtolnay/dissimilar/actions?query=branch%3Amaster)
+[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-dissimilar-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs" height="20">](https://docs.rs/dissimilar)
+[<img alt="build status" src="https://img.shields.io/github/actions/workflow/status/dtolnay/dissimilar/ci.yml?branch=master&style=for-the-badge" height="20">](https://github.com/dtolnay/dissimilar/actions?query=branch%3Amaster)
This library is a port of the Diff component of [Diff Match Patch] to Rust. The
diff implementation is based on [Myers' diff algorithm] but includes some
@@ -22,7 +22,7 @@ Diff Match Patch was originally built in 2006 to power Google Docs.
dissimilar = "1.0"
```
-*Compiler support: requires rustc 1.31+*
+*Compiler support: requires rustc 1.36+*
<br>
diff --git a/vendor/dissimilar/src/find.rs b/vendor/dissimilar/src/find.rs
index 90ca2c6c5..4af3b8bee 100644
--- a/vendor/dissimilar/src/find.rs
+++ b/vendor/dissimilar/src/find.rs
@@ -1,5 +1,5 @@
// The strstr implementation in this file is extracted from the Rust standard
-// library's str::find. The algorithm works for arbitrary &[u8] haystack and
+// library's str::find. The algorithm works for arbitrary &[T] haystack and
// needle but is only exposed by the standard library on UTF-8 strings.
//
// https://github.com/rust-lang/rust/blob/1.40.0/src/libcore/str/pattern.rs
@@ -80,7 +80,7 @@
use std::cmp;
use std::usize;
-pub fn find(haystack: &[u8], needle: &[u8]) -> Option<usize> {
+pub fn find(haystack: &[char], needle: &[char]) -> Option<usize> {
assert!(!needle.is_empty());
// crit_pos: critical factorization index
@@ -177,12 +177,12 @@ pub fn find(haystack: &[u8], needle: &[u8]) -> Option<usize> {
}
}
-fn byteset_create(bytes: &[u8]) -> u64 {
- bytes.iter().fold(0, |a, &b| (1 << (b & 0x3f)) | a)
+fn byteset_create(chars: &[char]) -> u64 {
+ chars.iter().fold(0, |a, &ch| (1 << (ch as u8 & 0x3f)) | a)
}
-fn byteset_contains(byteset: u64, byte: u8) -> bool {
- (byteset >> ((byte & 0x3f) as usize)) & 1 != 0
+fn byteset_contains(byteset: u64, ch: char) -> bool {
+ (byteset >> ((ch as u8 & 0x3f) as usize)) & 1 != 0
}
// Compute the maximal suffix of `arr`.
@@ -197,7 +197,7 @@ fn byteset_contains(byteset: u64, byte: u8) -> bool {
// a critical factorization.
//
// For long period cases, the resulting period is not exact (it is too short).
-fn maximal_suffix(arr: &[u8], order_greater: bool) -> (usize, usize) {
+fn maximal_suffix(arr: &[char], order_greater: bool) -> (usize, usize) {
let mut left = 0; // Corresponds to i in the paper
let mut right = 1; // Corresponds to j in the paper
let mut offset = 0; // Corresponds to k in the paper, but starting at 0
diff --git a/vendor/dissimilar/src/lib.rs b/vendor/dissimilar/src/lib.rs
index 8ce9faad3..b66434ade 100644
--- a/vendor/dissimilar/src/lib.rs
+++ b/vendor/dissimilar/src/lib.rs
@@ -2,7 +2,7 @@
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
-//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logoColor=white&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K
+//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
//!
//! <br>
//!
@@ -37,9 +37,10 @@
//! [Myers' diff algorithm]: https://neil.fraser.name/writing/diff/myers.pdf
//! [semantic cleanups]: https://neil.fraser.name/writing/diff/
-#![doc(html_root_url = "https://docs.rs/dissimilar/1.0.4")]
+#![doc(html_root_url = "https://docs.rs/dissimilar/1.0.6")]
#![allow(
clippy::blocks_in_if_conditions,
+ clippy::bool_to_int_with_if,
clippy::cast_possible_wrap,
clippy::cast_sign_loss,
clippy::cloned_instead_of_copied, // https://github.com/rust-lang/rust-clippy/issues/7127
@@ -63,10 +64,10 @@ mod range;
#[cfg(test)]
mod tests;
-use crate::range::{bytes, str, Range};
+use crate::range::{slice, Range};
use std::cmp;
use std::collections::VecDeque;
-use std::fmt::{self, Debug};
+use std::fmt::{self, Debug, Display, Write};
#[derive(Copy, Clone, PartialEq, Eq)]
pub enum Chunk<'a> {
@@ -121,20 +122,49 @@ impl<'tmp, 'a: 'tmp, 'b: 'tmp> Diff<'a, 'b> {
}
pub fn diff<'a>(text1: &'a str, text2: &'a str) -> Vec<Chunk<'a>> {
- let text1 = Range::new(text1, ..);
- let text2 = Range::new(text2, ..);
- let mut solution = main(text1, text2);
+ let chars1: Vec<char> = text1.chars().collect();
+ let chars2: Vec<char> = text2.chars().collect();
+ let range1 = Range::new(&chars1, ..);
+ let range2 = Range::new(&chars2, ..);
+
+ let mut solution = main(range1, range2);
cleanup_char_boundary(&mut solution);
cleanup_semantic(&mut solution);
cleanup_merge(&mut solution);
- solution.diffs.into_iter().map(Chunk::from).collect()
+
+ let mut chunks = Vec::new();
+ let mut pos1 = 0;
+ let mut pos2 = 0;
+ for diff in solution.diffs {
+ chunks.push(match diff {
+ Diff::Equal(range, _) => {
+ let len = range.len_bytes();
+ let chunk = Chunk::Equal(&text1[pos1..pos1 + len]);
+ pos1 += len;
+ pos2 += len;
+ chunk
+ }
+ Diff::Delete(range) => {
+ let len = range.len_bytes();
+ let chunk = Chunk::Delete(&text1[pos1..pos1 + len]);
+ pos1 += len;
+ chunk
+ }
+ Diff::Insert(range) => {
+ let len = range.len_bytes();
+ let chunk = Chunk::Insert(&text2[pos2..pos2 + len]);
+ pos2 += len;
+ chunk
+ }
+ });
+ }
+ chunks
}
struct Solution<'a, 'b> {
text1: Range<'a>,
text2: Range<'b>,
diffs: Vec<Diff<'a, 'b>>,
- utf8: bool,
}
fn main<'a, 'b>(mut text1: Range<'a>, mut text2: Range<'b>) -> Solution<'a, 'b> {
@@ -142,7 +172,7 @@ fn main<'a, 'b>(mut text1: Range<'a>, mut text2: Range<'b>) -> Solution<'a, 'b>
let whole2 = text2;
// Trim off common prefix.
- let common_prefix_len = common_prefix_bytes(text1, text2);
+ let common_prefix_len = common_prefix(text1, text2);
let common_prefix = Diff::Equal(
text1.substring(..common_prefix_len),
text2.substring(..common_prefix_len),
@@ -151,7 +181,7 @@ fn main<'a, 'b>(mut text1: Range<'a>, mut text2: Range<'b>) -> Solution<'a, 'b>
text2 = text2.substring(common_prefix_len..);
// Trim off common suffix.
- let common_suffix_len = common_suffix_bytes(text1, text2);
+ let common_suffix_len = common_suffix(text1, text2);
let common_suffix = Diff::Equal(
text1.substring(text1.len - common_suffix_len..),
text2.substring(text2.len - common_suffix_len..),
@@ -164,7 +194,6 @@ fn main<'a, 'b>(mut text1: Range<'a>, mut text2: Range<'b>) -> Solution<'a, 'b>
text1: whole1,
text2: whole2,
diffs: compute(text1, text2),
- utf8: false,
};
// Restore the prefix and suffix.
@@ -252,7 +281,7 @@ fn bisect<'a, 'b>(text1: Range<'a>, text2: Range<'b>) -> Vec<Diff<'a, 'b>> {
} as usize;
let mut y1 = (x1 as isize - k1) as usize;
if let (Some(s1), Some(s2)) = (text1.get(x1..), text2.get(y1..)) {
- let advance = common_prefix_bytes(s1, s2);
+ let advance = common_prefix(s1, s2);
x1 += advance;
y1 += advance;
}
@@ -288,7 +317,7 @@ fn bisect<'a, 'b>(text1: Range<'a>, text2: Range<'b>) -> Vec<Diff<'a, 'b>> {
} as usize;
let mut y2 = (x2 as isize - k2) as usize;
if x2 < text1.len && y2 < text2.len {
- let advance = common_suffix_bytes(
+ let advance = common_suffix(
text1.substring(..text1.len - x2),
text2.substring(..text2.len - y2),
);
@@ -342,8 +371,8 @@ fn bisect_split<'a, 'b>(
// Determine the length of the common prefix of two strings.
fn common_prefix(text1: Range, text2: Range) -> usize {
- for ((i, ch1), ch2) in text1.char_indices().zip(text2.chars()) {
- if ch1 != ch2 {
+ for (i, (b1, b2)) in text1.chars().zip(text2.chars()).enumerate() {
+ if b1 != b2 {
return i;
}
}
@@ -352,25 +381,7 @@ fn common_prefix(text1: Range, text2: Range) -> usize {
// Determine the length of the common suffix of two strings.
fn common_suffix(text1: Range, text2: Range) -> usize {
- for ((i, ch1), ch2) in text1.char_indices().rev().zip(text2.chars().rev()) {
- if ch1 != ch2 {
- return text1.len - i - ch1.len_utf8();
- }
- }
- cmp::min(text1.len, text2.len)
-}
-
-fn common_prefix_bytes(text1: Range, text2: Range) -> usize {
- for (i, (b1, b2)) in text1.bytes().zip(text2.bytes()).enumerate() {
- if b1 != b2 {
- return i;
- }
- }
- cmp::min(text1.len, text2.len)
-}
-
-fn common_suffix_bytes(text1: Range, text2: Range) -> usize {
- for (i, (b1, b2)) in text1.bytes().rev().zip(text2.bytes().rev()).enumerate() {
+ for (i, (b1, b2)) in text1.chars().rev().zip(text2.chars().rev()).enumerate() {
if b1 != b2 {
return i;
}
@@ -394,7 +405,7 @@ fn common_overlap(mut text1: Range, mut text2: Range) -> usize {
text2 = text2.substring(..text1.len);
}
// Quick check for the worst case.
- if bytes(text1) == bytes(text2) {
+ if slice(text1) == slice(text2) {
return text1.len;
}
@@ -411,7 +422,7 @@ fn common_overlap(mut text1: Range, mut text2: Range) -> usize {
};
length += found;
if found == 0
- || bytes(text1.substring(text1.len - length..)) == bytes(text2.substring(..length))
+ || slice(text1.substring(text1.len - length..)) == slice(text2.substring(..length))
{
best = length;
length += 1;
@@ -420,17 +431,24 @@ fn common_overlap(mut text1: Range, mut text2: Range) -> usize {
}
fn cleanup_char_boundary(solution: &mut Solution) {
- fn boundary_down(doc: &str, pos: usize) -> usize {
+ fn is_segmentation_boundary(doc: &[char], pos: usize) -> bool {
+ // FIXME: use unicode-segmentation crate?
+ let _ = doc;
+ let _ = pos;
+ true
+ }
+
+ fn boundary_down(doc: &[char], pos: usize) -> usize {
let mut adjust = 0;
- while !doc.is_char_boundary(pos - adjust) {
+ while !is_segmentation_boundary(doc, pos - adjust) {
adjust += 1;
}
adjust
}
- fn boundary_up(doc: &str, pos: usize) -> usize {
+ fn boundary_up(doc: &[char], pos: usize) -> usize {
let mut adjust = 0;
- while !doc.is_char_boundary(pos + adjust) {
+ while !is_segmentation_boundary(doc, pos + adjust) {
adjust += 1;
}
adjust
@@ -498,7 +516,6 @@ fn cleanup_char_boundary(solution: &mut Solution) {
}
solution.diffs.truncate(retain);
- solution.utf8 = true;
}
// Reduce the number of edits by eliminating semantically trivial equalities.
@@ -658,14 +675,13 @@ fn cleanup_semantic_lossless(solution: &mut Solution) {
&& !next_equal1.is_empty()
&& edit.text().chars().next().unwrap() == next_equal1.chars().next().unwrap()
{
- let increment = edit.text().chars().next().unwrap().len_utf8();
- prev_equal1.len += increment;
- prev_equal2.len += increment;
- edit.shift_right(increment);
- next_equal1.offset += increment;
- next_equal1.len -= increment;
- next_equal2.offset += increment;
- next_equal2.len -= increment;
+ prev_equal1.len += 1;
+ prev_equal2.len += 1;
+ edit.shift_right(1);
+ next_equal1.offset += 1;
+ next_equal1.len -= 1;
+ next_equal2.offset += 1;
+ next_equal2.len -= 1;
let score = cleanup_semantic_score(prev_equal1, edit.text())
+ cleanup_semantic_score(edit.text(), next_equal1);
// The >= encourages trailing rather than leading whitespace on edits.
@@ -720,8 +736,10 @@ fn cleanup_semantic_score(one: Range, two: Range) -> usize {
let whitespace2 = non_alphanumeric2 && char2.is_ascii_whitespace();
let line_break1 = whitespace1 && char1.is_control();
let line_break2 = whitespace2 && char2.is_control();
- let blank_line1 = line_break1 && (one.ends_with("\n\n") || one.ends_with("\n\r\n"));
- let blank_line2 = line_break2 && (two.starts_with("\n\n") || two.starts_with("\r\n\r\n"));
+ let blank_line1 =
+ line_break1 && (one.ends_with(['\n', '\n']) || one.ends_with(['\n', '\r', '\n']));
+ let blank_line2 =
+ line_break2 && (two.starts_with(['\n', '\n']) || two.starts_with(['\r', '\n', '\r', '\n']));
if blank_line1 || blank_line2 {
// Five points for blank lines.
@@ -747,22 +765,7 @@ fn cleanup_semantic_score(one: Range, two: Range) -> usize {
// move as long as it doesn't cross an equality.
fn cleanup_merge(solution: &mut Solution) {
let diffs = &mut solution.diffs;
- let common_prefix = if solution.utf8 {
- common_prefix
- } else {
- common_prefix_bytes
- };
- let common_suffix = if solution.utf8 {
- common_suffix
- } else {
- common_suffix_bytes
- };
-
- loop {
- if diffs.is_empty() {
- return;
- }
-
+ while !diffs.is_empty() {
diffs.push(Diff::Equal(
solution.text1.substring(solution.text1.len..),
solution.text2.substring(solution.text2.len..),
@@ -911,22 +914,22 @@ impl Debug for Chunk<'_> {
impl Debug for Diff<'_, '_> {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
- let (name, bytes) = match *self {
- Diff::Equal(range, _) => ("Equal", bytes(range)),
- Diff::Delete(range) => ("Delete", bytes(range)),
- Diff::Insert(range) => ("Insert", bytes(range)),
+ let (name, range) = match *self {
+ Diff::Equal(range, _) => ("Equal", range),
+ Diff::Delete(range) => ("Delete", range),
+ Diff::Insert(range) => ("Insert", range),
};
- let text = String::from_utf8_lossy(bytes);
- write!(formatter, "{}({:?})", name, text)
- }
-}
-
-impl<'a> From<Diff<'a, 'a>> for Chunk<'a> {
- fn from(diff: Diff<'a, 'a>) -> Self {
- match diff {
- Diff::Equal(range, _) => Chunk::Equal(str(range)),
- Diff::Delete(range) => Chunk::Delete(str(range)),
- Diff::Insert(range) => Chunk::Insert(str(range)),
+ formatter.write_str(name)?;
+ formatter.write_str("(\"")?;
+ for ch in range.chars() {
+ if ch == '\'' {
+ // escape_debug turns this into "\'" which is unnecessary.
+ formatter.write_char(ch)?;
+ } else {
+ Display::fmt(&ch.escape_debug(), formatter)?;
+ }
}
+ formatter.write_str("\")")?;
+ Ok(())
}
}
diff --git a/vendor/dissimilar/src/range.rs b/vendor/dissimilar/src/range.rs
index 565a94c06..55cbc448c 100644
--- a/vendor/dissimilar/src/range.rs
+++ b/vendor/dissimilar/src/range.rs
@@ -1,11 +1,10 @@
use crate::find::find;
use std::fmt::Debug;
use std::ops::{self, RangeFrom, RangeFull, RangeTo};
-use std::str::{CharIndices, Chars};
#[derive(Copy, Clone)]
pub struct Range<'a> {
- pub doc: &'a str,
+ pub doc: &'a [char],
pub offset: usize,
pub len: usize,
}
@@ -13,13 +12,13 @@ pub struct Range<'a> {
impl<'a> Range<'a> {
pub fn empty() -> Self {
Range {
- doc: "",
+ doc: &[],
offset: 0,
len: 0,
}
}
- pub fn new(doc: &'a str, bounds: impl RangeBounds) -> Self {
+ pub fn new(doc: &'a [char], bounds: impl RangeBounds) -> Self {
let (offset, len) = bounds.index(doc.len());
Range { doc, offset, len }
}
@@ -28,6 +27,10 @@ impl<'a> Range<'a> {
self.len == 0
}
+ pub fn len_bytes(&self) -> usize {
+ self.chars().map(char::len_utf8).sum()
+ }
+
pub fn substring(&self, bounds: impl RangeBounds) -> Self {
let (offset, len) = bounds.index(self.len);
Range {
@@ -50,32 +53,26 @@ impl<'a> Range<'a> {
(self.substring(..mid), self.substring(mid..))
}
- pub fn chars(&self) -> Chars<'a> {
- str(*self).chars()
- }
-
- pub fn char_indices(&self) -> CharIndices<'a> {
- str(*self).char_indices()
+ pub fn chars(
+ &self,
+ ) -> impl Iterator<Item = char> + DoubleEndedIterator + ExactSizeIterator + 'a {
+ slice(*self).iter().copied()
}
- pub fn bytes(&self) -> impl Iterator<Item = u8> + DoubleEndedIterator + ExactSizeIterator + 'a {
- bytes(*self).iter().cloned()
+ pub fn starts_with(&self, prefix: impl AsRef<[char]>) -> bool {
+ slice(*self).starts_with(prefix.as_ref())
}
- pub fn starts_with(&self, prefix: impl AsRef<[u8]>) -> bool {
- bytes(*self).starts_with(prefix.as_ref())
+ pub fn ends_with(&self, suffix: impl AsRef<[char]>) -> bool {
+ slice(*self).ends_with(suffix.as_ref())
}
- pub fn ends_with(&self, suffix: impl AsRef<[u8]>) -> bool {
- bytes(*self).ends_with(suffix.as_ref())
- }
-
- pub fn find(&self, needle: impl AsRef<[u8]>) -> Option<usize> {
- find(bytes(*self), needle.as_ref())
+ pub fn find(&self, needle: impl AsRef<[char]>) -> Option<usize> {
+ find(slice(*self), needle.as_ref())
}
}
-pub fn str(range: Range) -> &str {
+pub fn slice(range: Range) -> &[char] {
if cfg!(debug)
&& range
.doc
@@ -90,13 +87,9 @@ pub fn str(range: Range) -> &str {
&range.doc[range.offset..range.offset + range.len]
}
-pub fn bytes(range: Range) -> &[u8] {
- &range.doc.as_bytes()[range.offset..range.offset + range.len]
-}
-
-impl AsRef<[u8]> for Range<'_> {
- fn as_ref(&self) -> &[u8] {
- bytes(*self)
+impl AsRef<[char]> for Range<'_> {
+ fn as_ref(&self) -> &[char] {
+ slice(*self)
}
}
diff --git a/vendor/dissimilar/src/tests.rs b/vendor/dissimilar/src/tests.rs
index 450d7f7e4..d2e3fd643 100644
--- a/vendor/dissimilar/src/tests.rs
+++ b/vendor/dissimilar/src/tests.rs
@@ -1,4 +1,13 @@
use super::*;
+use once_cell::sync::OnceCell;
+
+macro_rules! range {
+ ($text:expr) => {{
+ static CHARS: OnceCell<Vec<char>> = OnceCell::new();
+ let chars = CHARS.get_or_init(|| $text.chars().collect());
+ Range::new(chars, ..)
+ }};
+}
macro_rules! diff_list {
() => {
@@ -6,50 +15,52 @@ macro_rules! diff_list {
text1: Range::empty(),
text2: Range::empty(),
diffs: Vec::new(),
- utf8: true,
}
};
($($kind:ident($text:literal)),+ $(,)?) => {{
+ #[allow(unused_macro_rules)]
macro_rules! text1 {
(Insert, $s:literal) => { "" };
(Delete, $s:literal) => { $s };
(Equal, $s:literal) => { $s };
}
+ #[allow(unused_macro_rules)]
macro_rules! text2 {
(Insert, $s:literal) => { $s };
(Delete, $s:literal) => { "" };
(Equal, $s:literal) => { $s };
}
- let text1 = concat!($(text1!($kind, $text)),*);
- let text2 = concat!($(text2!($kind, $text)),*);
+ let text1 = range!(concat!($(text1!($kind, $text)),*));
+ let text2 = range!(concat!($(text2!($kind, $text)),*));
let (_i, _j) = (&mut 0, &mut 0);
+ #[allow(unused_macro_rules)]
macro_rules! range {
(Insert, $s:literal) => {
- Diff::Insert(range(text2, _j, $s))
+ Diff::Insert(range(text2.doc, _j, $s))
};
(Delete, $s:literal) => {
- Diff::Delete(range(text1, _i, $s))
+ Diff::Delete(range(text1.doc, _i, $s))
};
(Equal, $s:literal) => {
- Diff::Equal(range(text1, _i, $s), range(text2, _j, $s))
+ Diff::Equal(range(text1.doc, _i, $s), range(text2.doc, _j, $s))
};
}
Solution {
- text1: Range::new(text1, ..),
- text2: Range::new(text2, ..),
+ text1,
+ text2,
diffs: vec![$(range!($kind, $text)),*],
- utf8: true,
}
}};
}
-fn range<'a>(doc: &'a str, offset: &mut usize, text: &str) -> Range<'a> {
+fn range<'a>(doc: &'a [char], offset: &mut usize, text: &str) -> Range<'a> {
+ let len = text.chars().count();
let range = Range {
doc,
offset: *offset,
- len: text.len(),
+ len,
};
- *offset += text.len();
+ *offset += len;
range
}
@@ -65,12 +76,16 @@ macro_rules! assert_diffs {
}
fn same_diffs(expected: &[Chunk], actual: &[Diff]) -> bool {
+ fn eq(expected: &str, actual: &Range) -> bool {
+ expected.chars().eq(slice(*actual).iter().copied())
+ }
+
expected.len() == actual.len()
&& expected.iter().zip(actual).all(|pair| match pair {
- (Chunk::Insert(expected), Diff::Insert(actual)) => *expected == str(*actual),
- (Chunk::Delete(expected), Diff::Delete(actual)) => *expected == str(*actual),
+ (Chunk::Insert(expected), Diff::Insert(actual)) => eq(expected, actual),
+ (Chunk::Delete(expected), Diff::Delete(actual)) => eq(expected, actual),
(Chunk::Equal(expected), Diff::Equal(actual1, actual2)) => {
- *expected == str(*actual1) && *expected == str(*actual2)
+ eq(expected, actual1) && eq(expected, actual2)
}
(_, _) => false,
})
@@ -78,59 +93,56 @@ fn same_diffs(expected: &[Chunk], actual: &[Diff]) -> bool {
#[test]
fn test_common_prefix() {
- let text1 = Range::new("abc", ..);
- let text2 = Range::new("xyz", ..);
- assert_eq!(0, common_prefix_bytes(text1, text2), "Null case");
+ let text1 = range!("abc");
+ let text2 = range!("xyz");
+ assert_eq!(0, common_prefix(text1, text2), "Null case");
- let text1 = Range::new("1234abcdef", ..);
- let text2 = Range::new("1234xyz", ..);
- assert_eq!(4, common_prefix_bytes(text1, text2), "Non-null case");
+ let text1 = range!("1234abcdef");
+ let text2 = range!("1234xyz");
+ assert_eq!(4, common_prefix(text1, text2), "Non-null case");
- let text1 = Range::new("1234", ..);
- let text2 = Range::new("1234xyz", ..);
- assert_eq!(4, common_prefix_bytes(text1, text2), "Whole case");
+ let text1 = range!("1234");
+ let text2 = range!("1234xyz");
+ assert_eq!(4, common_prefix(text1, text2), "Whole case");
}
#[test]
fn test_common_suffix() {
- let text1 = Range::new("abc", ..);
- let text2 = Range::new("xyz", ..);
+ let text1 = range!("abc");
+ let text2 = range!("xyz");
assert_eq!(0, common_suffix(text1, text2), "Null case");
- assert_eq!(0, common_suffix_bytes(text1, text2), "Null case");
- let text1 = Range::new("abcdef1234", ..);
- let text2 = Range::new("xyz1234", ..);
+ let text1 = range!("abcdef1234");
+ let text2 = range!("xyz1234");
assert_eq!(4, common_suffix(text1, text2), "Non-null case");
- assert_eq!(4, common_suffix_bytes(text1, text2), "Non-null case");
- let text1 = Range::new("1234", ..);
- let text2 = Range::new("xyz1234", ..);
+ let text1 = range!("1234");
+ let text2 = range!("xyz1234");
assert_eq!(4, common_suffix(text1, text2), "Whole case");
- assert_eq!(4, common_suffix_bytes(text1, text2), "Whole case");
}
#[test]
fn test_common_overlap() {
let text1 = Range::empty();
- let text2 = Range::new("abcd", ..);
+ let text2 = range!("abcd");
assert_eq!(0, common_overlap(text1, text2), "Null case");
- let text1 = Range::new("abc", ..);
- let text2 = Range::new("abcd", ..);
+ let text1 = range!("abc");
+ let text2 = range!("abcd");
assert_eq!(3, common_overlap(text1, text2), "Whole case");
- let text1 = Range::new("123456", ..);
- let text2 = Range::new("abcd", ..);
+ let text1 = range!("123456");
+ let text2 = range!("abcd");
assert_eq!(0, common_overlap(text1, text2), "No overlap");
- let text1 = Range::new("123456xxx", ..);
- let text2 = Range::new("xxxabcd", ..);
+ let text1 = range!("123456xxx");
+ let text2 = range!("xxxabcd");
assert_eq!(3, common_overlap(text1, text2), "Overlap");
// Some overly clever languages (C#) may treat ligatures as equal to their
// component letters. E.g. U+FB01 == 'fi'
- let text1 = Range::new("fi", ..);
- let text2 = Range::new("\u{fb01}i", ..);
+ let text1 = range!("fi");
+ let text2 = range!("\u{fb01}i");
assert_eq!(0, common_overlap(text1, text2), "Unicode");
}
@@ -420,13 +432,12 @@ fn test_cleanup_semantic() {
#[test]
fn test_bisect() {
- let text1 = Range::new("cat", ..);
- let text2 = Range::new("map", ..);
+ let text1 = range!("cat");
+ let text2 = range!("map");
let solution = Solution {
text1,
text2,
diffs: bisect(text1, text2),
- utf8: false,
};
assert_diffs!(
[
@@ -446,24 +457,24 @@ fn test_main() {
let solution = main(Range::empty(), Range::empty());
assert_diffs!([], solution, "Null case");
- let solution = main(Range::new("abc", ..), Range::new("abc", ..));
+ let solution = main(range!("abc"), range!("abc"));
assert_diffs!([Equal("abc")], solution, "Equality");
- let solution = main(Range::new("abc", ..), Range::new("ab123c", ..));
+ let solution = main(range!("abc"), range!("ab123c"));
assert_diffs!(
[Equal("ab"), Insert("123"), Equal("c")],
solution,
"Simple insertion",
);
- let solution = main(Range::new("a123bc", ..), Range::new("abc", ..));
+ let solution = main(range!("a123bc"), range!("abc"));
assert_diffs!(
[Equal("a"), Delete("123"), Equal("bc")],
solution,
"Simple deletion",
);
- let solution = main(Range::new("abc", ..), Range::new("a123b456c", ..));
+ let solution = main(range!("abc"), range!("a123b456c"));
assert_diffs!(
[
Equal("a"),
@@ -476,7 +487,7 @@ fn test_main() {
"Two insertions",
);
- let solution = main(Range::new("a123b456c", ..), Range::new("abc", ..));
+ let solution = main(range!("a123b456c"), range!("abc"));
assert_diffs!(
[
Equal("a"),
@@ -489,12 +500,12 @@ fn test_main() {
"Two deletions",
);
- let solution = main(Range::new("a", ..), Range::new("b", ..));
+ let solution = main(range!("a"), range!("b"));
assert_diffs!([Delete("a"), Insert("b")], solution, "Simple case #1");
let solution = main(
- Range::new("Apples are a fruit.", ..),
- Range::new("Bananas are also fruit.", ..),
+ range!("Apples are a fruit."),
+ range!("Bananas are also fruit."),
);
assert_diffs!(
[
@@ -508,7 +519,7 @@ fn test_main() {
"Simple case #2",
);
- let solution = main(Range::new("ax\t", ..), Range::new("\u{0680}x\000", ..));
+ let solution = main(range!("ax\t"), range!("\u{0680}x\000"));
assert_diffs!(
[
Delete("a"),
@@ -521,7 +532,7 @@ fn test_main() {
"Simple case #3",
);
- let solution = main(Range::new("1ayb2", ..), Range::new("abxab", ..));
+ let solution = main(range!("1ayb2"), range!("abxab"));
assert_diffs!(
[
Delete("1"),
@@ -535,7 +546,7 @@ fn test_main() {
"Overlap #1",
);
- let solution = main(Range::new("abcy", ..), Range::new("xaxcxabc", ..));
+ let solution = main(range!("abcy"), range!("xaxcxabc"));
assert_diffs!(
[Insert("xaxcx"), Equal("abc"), Delete("y")],
solution,
@@ -543,8 +554,8 @@ fn test_main() {
);
let solution = main(
- Range::new("ABCDa=bcd=efghijklmnopqrsEFGHIJKLMNOefg", ..),
- Range::new("a-bcd-efghijklmnopqrs", ..),
+ range!("ABCDa=bcd=efghijklmnopqrsEFGHIJKLMNOefg"),
+ range!("a-bcd-efghijklmnopqrs"),
);
assert_diffs!(
[
@@ -563,8 +574,8 @@ fn test_main() {
);
let solution = main(
- Range::new("a [[Pennsylvania]] and [[New", ..),
- Range::new(" and [[Pennsylvania]]", ..),
+ range!("a [[Pennsylvania]] and [[New"),
+ range!(" and [[Pennsylvania]]"),
);
assert_diffs!(
[
diff --git a/vendor/dissimilar/tests/test.rs b/vendor/dissimilar/tests/test.rs
index e68fd4f11..7debb0593 100644
--- a/vendor/dissimilar/tests/test.rs
+++ b/vendor/dissimilar/tests/test.rs
@@ -21,7 +21,7 @@ fn test_unicode() {
}
#[test]
-fn test_unicode2() {
+fn test_issue9() {
let a = "[乀丁abcd一]";
let b = "[一abcd丁]";
let d = diff(a, b);
@@ -35,6 +35,18 @@ fn test_unicode2() {
Chunk::Delete("一"),
Chunk::Insert("丁"),
Chunk::Equal("]"),
- ]
+ ],
+ );
+}
+
+#[test]
+fn test_issue15() {
+ let a = "A のダ";
+ let b = "A ダ";
+ let d = diff(a, b);
+
+ assert_eq!(
+ d,
+ vec![Chunk::Equal("A "), Chunk::Delete("の"), Chunk::Equal("ダ")],
);
}