diff --git a/sample_files/compare.expected b/sample_files/compare.expected
index db0c2b663..950947509 100644
--- a/sample_files/compare.expected
+++ b/sample_files/compare.expected
@@ -1,14 +1,14 @@
sample_files/Session_1.kt sample_files/Session_2.kt
-a5899a29b0ebb0800923ac368b95fa1e -
+fec9f5421c5bdb3cb485c2cfd2f336a6 -
sample_files/ada_1.adb sample_files/ada_2.adb
-0f5fafa73393305ea0d6aba11149efd2 -
+7498a465384992689732536fcf6ec19b -
sample_files/added_line_1.txt sample_files/added_line_2.txt
8a1587e6b5fc53f2ec2ac665a5d00372 -
sample_files/align_footer_1.txt sample_files/align_footer_2.txt
-0c2a263268f6c1dd27aa5e6aed686b6c -
+a7ed15e00ccc8094621e2a9d3c29449c -
sample_files/all_changed_1.js sample_files/all_changed_2.js
6f6cbd4d2ed1045e3883143787dbd75b -
@@ -17,94 +17,97 @@ sample_files/apex_1.cls sample_files/apex_2.cls
8e477350907734ac4d5201752523dff3 -
sample_files/b2_math_1.h sample_files/b2_math_2.h
-1ab24165d072f91be11893b92bc0943f -
+ea7421bd7970a6edf2897f8785053ce4 -
sample_files/bad_combine_1.rs sample_files/bad_combine_2.rs
-dabc6d2f9df43eeaebdbbb44e23a73bb -
+a6d674bd88d54f085c22c70c2d5a4c80 -
sample_files/big_text_hunk_1.txt sample_files/big_text_hunk_2.txt
fc26d41a5ff771670e04033b177973d2 -
sample_files/change_outer_1.el sample_files/change_outer_2.el
-13d4673474ea6c7ee980f8a955fff26b -
+ae93896664a63c1f0d4a5f9c4d26dd70 -
sample_files/chinese_1.po sample_files/chinese_2.po
-0c40e3f3093cdda64ac9c9674ded3bce -
+582b2c28cca7a60b7c6b0410dfa436bc -
sample_files/clojure_1.clj sample_files/clojure_2.clj
-cdc99aad6117c0cfc2e6896fe629876e -
+f1a045dfa78cac71d355951fe0b363a0 -
sample_files/comma_1.js sample_files/comma_2.js
-0e29285c944ffe768790ffbbf9542470 -
+dfd18ec953d29545380fa656e54ff70e -
sample_files/comma_and_comment_1.js sample_files/comma_and_comment_2.js
0a5ccbcd368607e62eaff0c4ae25049f -
sample_files/comments_1.rs sample_files/comments_2.rs
-a75827163654d6aed8f837bb586e733c -
+d8c3c256de454bc23944cf1a4300c66e -
sample_files/context_1.rs sample_files/context_2.rs
-1a1633bcf672a582867c815381ae1609 -
+9b84c492d07d125912de77002bcaad9a -
sample_files/contiguous_1.js sample_files/contiguous_2.js
-22da862378dbee68e55ecba8b0fcec42 -
+7ac6081dee02e3529a88defca194bc00 -
sample_files/css_1.css sample_files/css_2.css
-3d911704ac4d76697c748e1dcd40eece -
+43a2bbc8dc2f4b4733ecb5a888d10dfc -
sample_files/dart_1.dart sample_files/dart_2.dart
107d073c2922ff14e9ba66ee0f489592 -
sample_files/devicetree_1.dts sample_files/devicetree_2.dts
-7ab2bd26334b6729a481665e5566cf97 -
+100d21f4d762db8991757b489c794db1 -
sample_files/elisp_1.el sample_files/elisp_2.el
-d7bdaf5f87e1c44475774c6e7ba70822 -
+3e8c8abcb65a5141a2fb54bae4a9ca06 -
sample_files/elisp_contiguous_1.el sample_files/elisp_contiguous_2.el
4a5a33873a4f84ee055d95e1448fba35 -
sample_files/elixir_1.ex sample_files/elixir_2.ex
-85494310196ac5065b3b4ce1d4b350fd -
+5ab1a845f7cb3ca6db1fdef7bc4a042f -
sample_files/elm_1.elm sample_files/elm_2.elm
-ccc1f4bb568cd72781dbcd623b612c43 -
+8a67269f2dd2e4913f885b3b6e6d6a07 -
sample_files/elvish_1.elv sample_files/elvish_2.elv
93af1d46752d57db84011ca7482ae842 -
sample_files/erlang_1.erl sample_files/erlang_2.erl
-4c3e2bd1f0918ed339e87a5f8e0b05cb -
+268056b80b3311309a17a6c5485f68cd -
sample_files/f_sharp_1.fs sample_files/f_sharp_2.fs
-25253b18ef64469c67cf9a7131c8c125 -
+f6c90edd5c4fb81b793f3b7c9b367845 -
sample_files/hack_1.php sample_files/hack_2.php
c2bb0aa7d7b07d6ced79f6a5363e878b -
sample_files/hare_1.ha sample_files/hare_2.ha
-ef6fd59edc55241311a97d21dd81e4c0 -
+b0d0b2c446b46285c585a8eca75e6dd3 -
sample_files/haskell_1.hs sample_files/haskell_2.hs
-68fd7f9865c2b1defe05ffd509e08b93 -
+e47ca7a69c6f90d9ed9e8b9d47eb2cd4 -
sample_files/hcl_1.hcl sample_files/hcl_2.hcl
-7c2aaa3a8b401bc007817f5dd608946d -
+b4de7a8269018e05c0eba247d8097111 -
sample_files/hello_world_1.smali sample_files/hello_world_2.smali
-c6a0a04710c1dbf30cec4ebed4a35ec9 -
+bb8463618fcb7f263bd2dafeef7a8b06 -
sample_files/helpful_1.el sample_files/helpful_2.el
-295640aa4cbc23640658a80ad2393ce4 -
+6eda1c77cb5dc13bc321e90e41a6b64d -
sample_files/html_1.html sample_files/html_2.html
-3cc8b445a56b74f05e1d7bb84874edab -
+2b873fd1ea8f77d2463ceb08aa23967c -
sample_files/html_simple_1.html sample_files/html_simple_2.html
-bb129dce38cd26eac81ca52d2016bade -
+4122689b7d2e3d59d822d2a5d93ebdd0 -
sample_files/huge_cpp_1.cpp sample_files/huge_cpp_2.cpp
-09e8a30ad7be5686e4d03a3e6b2588aa -
+05d96cce94db8ebdfaf4f2d52239470c -
+
+sample_files/hyphen_subwords_1.json sample_files/hyphen_subwords_2.json
+d0728537a824a0404a910b5b8dc05b1b -
sample_files/identical_1.scala sample_files/identical_2.scala
15c5a789e644348cb7e0de051ff4b63e -
@@ -116,61 +119,61 @@ sample_files/insert_blank_1.txt sample_files/insert_blank_2.txt
a5fd75afcc99aa7b2b285f1f9ced8607 -
sample_files/janet_1.janet sample_files/janet_2.janet
-4dba18ec3a9eeee68da7dcccba0fe5a5 -
+7dc0f1a3ce49f489fa4b64edefebb3c5 -
sample_files/java_1.java sample_files/java_2.java
-028c9176ac031eb3859f3d04bc43ed10 -
+f4b15ddf3283e6c14d200efd06c0e85a -
sample_files/javascript_1.js sample_files/javascript_2.js
-96bc1817594be11dfba02ad675aba076 -
+7fc853454d1133da215c646732ac67f3 -
sample_files/javascript_simple_1.js sample_files/javascript_simple_2.js
-449a5a824892da502f7211714214684e -
+1a2fdfb7210a93c80a7ce7c0768920c3 -
sample_files/json_1.json sample_files/json_2.json
-133c9224b47a5ee9940536a6ad70fd2e -
+2ac602e995cdcb4bbbc1be6f4622e296 -
sample_files/jsx_1.jsx sample_files/jsx_2.jsx
-712ef0cf61b469bbacc84b53b944e5ff -
+89832bde34f9c54c99a1bfb0f68291a9 -
sample_files/julia_1.jl sample_files/julia_2.jl
-532405b3959d8864c06d2fb3548df119 -
+10ac32ea1bd1d48b20386f1deeca40a0 -
sample_files/load_1.js sample_files/load_2.js
-289f061e6f36e009f646fb927335326a -
+2e47b7908951ff8390058856edbaf715 -
sample_files/long_line_1.txt sample_files/long_line_2.txt
7fc50bd547f0c20fda89a1931e5eb61e -
sample_files/lua_1.lua sample_files/lua_2.lua
-81ad9478e64494320e96284cb7632ced -
+11693bb34168541f2ac9f4154d246038 -
sample_files/makefile_1.mk sample_files/makefile_2.mk
-4759883325ade33566f2c8afa09e2d82 -
+1a132d165294d0325f9b0dae5569a4d0 -
sample_files/many_newlines_1.txt sample_files/many_newlines_2.txt
52ca05855e520876479e6f608c5e7831 -
sample_files/metadata_1.clj sample_files/metadata_2.clj
-fd0fee4a660e938c44182e6f77746d0e -
+b788a546c4ccc5662e98ed30473dd776 -
sample_files/modules_1.ml sample_files/modules_2.ml
-8584f755c99a93dd744a6722596a4418 -
+d0a10fce6354902c0a1708571ab17ffc -
sample_files/multibyte_1.py sample_files/multibyte_2.py
-f761255d521267ace4f4887a21664a12 -
+222fad0d771916afb86dfede9906895b -
sample_files/multiline_string_1.ml sample_files/multiline_string_2.ml
ed80815053ba156505d156277d0f4195 -
sample_files/multiline_string_eof_1.yml sample_files/multiline_string_eof_2.yml
-cd9cfd627c28b8ecd7c990adc683281a -
+79f24009a062f256054cf36e0317dc5d -
sample_files/nest_1.rs sample_files/nest_2.rs
-d3a799fe2cd9d81aa251c96af5cd9711 -
+bb3c526d9400776ffae5bf78631fa0c3 -
sample_files/nested_slider_1.el sample_files/nested_slider_2.el
-0880b11fd8a2e1245622f1f2a908e0c4 -
+7691443ec4ab9d35837f7caa5bfad2de -
sample_files/nested_slider_1.rs sample_files/nested_slider_2.rs
342df46db959e8c90925ff4400c0fa63 -
@@ -179,31 +182,31 @@ sample_files/nesting_1.el sample_files/nesting_2.el
cf32f6b798a080a2bf14a430337ac4a6 -
sample_files/newick_1.nwk sample_files/newick_2.nwk
-4244a6609827bae5dabb01b91c9cbd37 -
+bbc830fc20d60c5fdca7a99edc3fde78 -
sample_files/nix_1.nix sample_files/nix_2.nix
-6f9bea063047d66e9f857123dfe95e10 -
+5f591ced7633a07f13cdda9766110715 -
sample_files/nullable_1.kt sample_files/nullable_2.kt
d0a51e7201cc16dc6bcb99cbad64f6be -
sample_files/objc_header_1.h sample_files/objc_header_2.h
-122f030f33e779fb60d0ee83d5a187f4 -
+37267814a3d241a8f1497ef3239b360c -
sample_files/objc_module_1.m sample_files/objc_module_2.m
-f6c69d2b8b283619f5e093b689e7eb23 -
+63d3b15c53dfcb54c5cf6ff10c22a965 -
sample_files/ocaml_1.ml sample_files/ocaml_2.ml
-20586eb6dedffb55c7a9e264ed3739c9 -
+e99bb9f1f789bce0e9a1d4e5205b8139 -
sample_files/outer_delimiter_1.el sample_files/outer_delimiter_2.el
971c3ddebfae222ded24f7a97ec7b5d7 -
sample_files/pascal_1.pascal sample_files/pascal_2.pascal
-4e8dbdc95cbaba358cbc5dfa4cb22a55 -
+de04f7fdb7af7bd70ca62f1868504f11 -
sample_files/perl_1.pl sample_files/perl_2.pl
-e90ef13054f1e541addcac5ee4bad880 -
+2cd2638b2b6d07248911f1f2e5ad1b25 -
sample_files/prefer_outer_1.el sample_files/prefer_outer_2.el
991038c9988cccc2c824652e33f772a2 -
@@ -212,25 +215,25 @@ sample_files/preprocessor_1.h sample_files/preprocessor_2.h
d94f452bbf7cb3accc8d538fdd7ab5e4 -
sample_files/qml_1.qml sample_files/qml_2.qml
-26fed88e46817e49c59fe466701ee574 -
+ec69003436e7780633b6224861c3cccf -
sample_files/r_1.R sample_files/r_2.R
-f9ee6c271d614bfcd510633bddc9e49d -
+f86f4d5f494756079a4ccfdc17521ef3 -
sample_files/racket_1.rkt sample_files/racket_2.rkt
-ba1164af47f67d0865a4ba7706096bbc -
+4debb7e7af49678aa19726acb5c55d7d -
sample_files/repeated_line_no_eol_1.txt sample_files/repeated_line_no_eol_2.txt
b63c743f2133480de3ba42ecdec5eb93 -
sample_files/ruby_1.rb sample_files/ruby_2.rb
-af0b05e67f4338db6be0fd21454c6a08 -
+a0a7121421e3d57acadc08519275dcce -
sample_files/scala_1.scala sample_files/scala_2.scala
-13181dc30f15675747ce5315cd8073e6 -
+2304bea82a6dae573964afdaeb47f845 -
sample_files/scheme_1.scm sample_files/scheme_2.scm
-09f8683219a8491c22d9a2fa1ce98c16 -
+2d18a48f788361085a05812c2446de91 -
sample_files/simple_1.js sample_files/simple_2.js
1d49d0e440067284015eb5621f4a6adf -
@@ -242,13 +245,13 @@ sample_files/simple_1.txt sample_files/simple_2.txt
7df04bd5dbc68a2392b2f0b375c4413e -
sample_files/slider_1.rs sample_files/slider_2.rs
-346155adadb1340c026bbfa5cfd5669d -
+ebdc9db32892d1d74f7e745f45fbaba6 -
sample_files/slider_at_end_1.json sample_files/slider_at_end_2.json
-cb370f1c0ccc5e155743330629f899f0 -
+6c994cd99226f6584f74f531bb27d54f -
sample_files/slow_1.rs sample_files/slow_2.rs
-74dcf4792d2dc7d7e03ee367aadc3b3c -
+4eabdb287f5fa31f5765117f4874d218 -
sample_files/small_1.js sample_files/small_2.js
86b1132b6c17fcc2cbec65b1c248baa9 -
@@ -257,65 +260,65 @@ sample_files/sql_1.sql sample_files/sql_2.sql
ee54ee3f974aa54c8bdfc2b9075824f2 -
sample_files/string_subwords_1.el sample_files/string_subwords_2.el
-b66e960672189960c2d35ef68b47a195 -
+5c72eae6a018e26189868bcc28747c72 -
sample_files/strings_1.el sample_files/strings_2.el
-26ea57243abb16043088b17bfee482a4 -
+ae3b58de9c115cac8a1044e6cdf77723 -
sample_files/swift_1.swift sample_files/swift_2.swift
73830b14bd8aacac8d4590a3bed61c40 -
sample_files/syntax_error_1.js sample_files/syntax_error_2.js
-5bbd81f688bdcfbdbdf69d870f0c1357 -
+c3b918adc3e37f06c65e76fdd4f967e3 -
sample_files/tab_1.c sample_files/tab_2.c
-a7f9bce0ca76ce356413fb218d82d686 -
+3e19a5dfb37bcda0fbc20e0446c65692 -
sample_files/tab_1.txt sample_files/tab_2.txt
-a17e978720fe4c1b25614402910cc695 -
+10e9a853917dc9d92d2867e3453269b2 -
sample_files/tailwind_1.css sample_files/tailwind_2.css
132f217659bf9dac8b82feabf5643f47 -
sample_files/text_1.txt sample_files/text_2.txt
-f8f81946284fc625ac8e9ae441f31e6d -
+caa98983e0fc26ae2bc833ae90fb0a1c -
sample_files/todomvc_1.gleam sample_files/todomvc_2.gleam
6b3b8c9f1e813617819b97144cc5cc4a -
sample_files/toml_1.toml sample_files/toml_2.toml
-c331bdb54c00b0a5b5a622dbd250042a -
+e1002ceba14d973fcc8abc23619e65b0 -
sample_files/trailling_newline_1.yaml sample_files/trailling_newline_2.yaml
8e37febfec957288576f9c2020cfc4f2 -
sample_files/typescript_1.ts sample_files/typescript_2.ts
-fee7ee33d2037ad1941ba6bb5532a1db -
+e15ceae53da7cfb308960f8c3f30b891 -
sample_files/typing_1.ml sample_files/typing_2.ml
-975a97f2a6798abd1e4c0ce219e183fd -
+ae41c3f5aa1ba13c2a424d3afa7ece6c -
sample_files/utf16_1.py sample_files/utf16_2.py
-3bcee785d4cebc38a42eafe49a198b52 -
+58f2fd906a5ed1b7c5d933bb380c5a1c -
sample_files/verilog_1.sv sample_files/verilog_2.sv
-2f59632b5a4e5addfa7b4d5274da72cc -
+0fbb9bd8ff99b8ee852741860d2c25d0 -
sample_files/vhdl_1.vhd sample_files/vhdl_2.vhd
-ca98b4d14fc21e0f04cf24aeb3d2526c -
+d23ea3d27a4cba037729adf485c84afa -
sample_files/whitespace_1.tsx sample_files/whitespace_2.tsx
-6449f177ecbaadbbf97d2eedfbf26f16 -
+789689b170b80ef280a322b3a6c7363b -
sample_files/windows1251_1.txt sample_files/windows1251_2.txt
-9ebe6bb440ac2e630f889827b98d4714 -
+28cb8832f6b172c34a28082012512269 -
sample_files/xml_1.xml sample_files/xml_2.xml
-e629cbd2e721fd249c7ce1626f17e953 -
+d943cb3ae6ea5a5b933ceb1b9987c06b -
sample_files/yaml_1.yaml sample_files/yaml_2.yaml
-521a2075e4f8b0ea9fb74436e0445b52 -
+a539973fd87b6f1fe1391ce73a9b9f90 -
sample_files/zig_1.zig sample_files/zig_2.zig
-2cb2ce5bcb62c02a29da7ce8a33c6265 -
+f548aaa131854792fe3b72bc283f1280 -
diff --git a/src/display/style.rs b/src/display/style.rs
index 28d480e31..7a6e54179 100644
--- a/src/display/style.rs
+++ b/src/display/style.rs
@@ -324,6 +324,48 @@ pub(crate) fn novel_style(style: Style, side: Side, background: BackgroundColor)
}
}
+/// Merge spans where the end of one span matches the start of the
+/// next span.
+///
+/// This reduces the number of ANSI character codes in the
+/// output. This is negligible for performance, but makes regression
+/// testing easier for difftastic.
+///
+/// The file compare.expected contains hashes of the output, so it
+/// considers `ab` to be distinct from
+/// `ab`. Merging the spans normalises
+/// the output to `ab`.
+fn merge_adjacent(items: &[(SingleLineSpan, Style)]) -> Vec<(SingleLineSpan, Style)> {
+ let mut merged: Vec<(SingleLineSpan, Style)> = vec![];
+ let mut prev_item: Option<(SingleLineSpan, Style)> = None;
+
+ for (span, style) in items.iter().copied() {
+ match prev_item.take() {
+ Some((mut prev_span, prev_style)) => {
+ if prev_style == style
+ && prev_span.line == span.line
+ && prev_span.end_col == span.start_col
+ {
+ prev_span.end_col = span.end_col;
+ prev_item = Some((prev_span, style));
+ } else {
+ merged.push((prev_span, prev_style));
+ prev_item = Some((span, style));
+ }
+ }
+ None => {
+ prev_item = Some((span, style));
+ }
+ }
+ }
+
+ if let Some(last_item) = prev_item {
+ merged.push(last_item);
+ }
+
+ merged
+}
+
pub(crate) fn color_positions(
side: Side,
background: BackgroundColor,
@@ -402,7 +444,8 @@ pub(crate) fn color_positions(
};
styles.push((mp.pos, style));
}
- styles
+
+ merge_adjacent(&styles)
}
pub(crate) fn apply_colors(