Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package mergiraf for openSUSE:Factory checked in at 2026-09-28 10:45:52 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/mergiraf (Old) and /work/SRC/openSUSE:Factory/.mergiraf.new.383539 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "mergiraf" Mon Sep 28 10:45:52 2026 rev:14 rq:1380799 version:0.20.0 Changes: -------- --- /work/SRC/openSUSE:Factory/mergiraf/mergiraf.changes 2026-09-01 15:52:36.757665291 +0200 +++ /work/SRC/openSUSE:Factory/.mergiraf.new.383539/mergiraf.changes 2026-09-28 10:46:28.972028556 +0200 @@ -1,0 +2,25 @@ +Sat Sep 26 13:41:57 UTC 2026 - Andrei Dziahel <[email protected]> + +- Update to version 0.20.0: + * Features + + QML Language Support (#810) by @mward25 + * Bug Fixes + + (mgf_dev) Restore proper logging, add verbosity control + (#821) by @wetneb + + Name the file in the structured merge timeout warning + (#828) by @robvenn + * Performance + + Compile tree-sitter queries once per parse (#839) by @HALtheWise + * Testing + + Utilities to benchmark mergiraf on large corpora (#537) + by @wetneb + * Miscellaneous Tasks + + Restore build.rs to refresh test binary if test data changed + (#822) by @wetneb + + Update NodeJS in CI (#834) by @wetneb + * New Contributors + + @HALtheWise made their first contribution in #839 + + @mward25 made their first contribution in #810 + + @robvenn made their first contribution in #828 + +------------------------------------------------------------------- Old: ---- mergiraf-0.19.1.obscpio New: ---- mergiraf-0.20.0.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ mergiraf.spec ++++++ --- /var/tmp/diff_new_pack.qp6Fkw/_old 2026-09-28 10:46:30.433089769 +0200 +++ /var/tmp/diff_new_pack.qp6Fkw/_new 2026-09-28 10:46:30.435089853 +0200 @@ -18,7 +18,7 @@ Name: mergiraf -Version: 0.19.1 +Version: 0.20.0 Release: 0 Summary: A syntax-aware git merge driver License: GPL-3.0-or-later ++++++ _service ++++++ --- /var/tmp/diff_new_pack.qp6Fkw/_old 2026-09-28 10:46:30.501092618 +0200 +++ /var/tmp/diff_new_pack.qp6Fkw/_new 2026-09-28 10:46:30.508092912 +0200 @@ -3,7 +3,7 @@ <param name="url">https://codeberg.org/mergiraf/mergiraf.git</param> <param name="versionformat">@PARENT_TAG@</param> <param name="scm">git</param> - <param name="revision">v0.19.1</param> + <param name="revision">v0.20.0</param> <param name="versionrewrite-pattern">v(\d+\.\d+\.\d+)</param> <param name="changesgenerate">enable</param> </service> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.qp6Fkw/_old 2026-09-28 10:46:30.538094169 +0200 +++ /var/tmp/diff_new_pack.qp6Fkw/_new 2026-09-28 10:46:30.542094336 +0200 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://codeberg.org/mergiraf/mergiraf.git</param> - <param name="changesrevision">e1c6514fb364faca51132be2b336aa739cdfadb9</param></service></servicedata> + <param name="changesrevision">182d26ea63aa62f7f5dc213cf8ceb70d83e7750e</param></service></servicedata> (No newline at EOF) ++++++ mergiraf-0.19.1.obscpio -> mergiraf-0.20.0.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/.forgejo/workflows/Dockerfile new/mergiraf-0.20.0/.forgejo/workflows/Dockerfile --- old/mergiraf-0.19.1/.forgejo/workflows/Dockerfile 2026-09-01 10:50:21.000000000 +0200 +++ new/mergiraf-0.20.0/.forgejo/workflows/Dockerfile 2026-09-26 11:02:58.000000000 +0200 @@ -18,3 +18,7 @@ # Install 'shellcheck' RUN apt-get install shellcheck + +# Install a newer nodejs +# TODO: this should be dropped once we migrate to act-26 (it's not out yet as of 2026-09-24) +RUN curl -fsSL https://deb.nodesource.com/setup_24.x | sudo -E bash - && sudo apt-get install -y nodejs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/Cargo.lock new/mergiraf-0.20.0/Cargo.lock --- old/mergiraf-0.19.1/Cargo.lock 2026-09-01 10:50:21.000000000 +0200 +++ new/mergiraf-0.20.0/Cargo.lock 2026-09-26 11:02:58.000000000 +0200 @@ -146,9 +146,9 @@ [[package]] name = "cc" -version = "1.4.3" +version = "1.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "509591b7bcd67f4ef775afad7662703b4935daaa6ec0e5605cfb1090b32a2b6d" +checksum = "54413ede23c2daf518f35156dfde027feb2374004d63bd497f983c8db9c0e313" dependencies = [ "find-msvc-tools", "shlex", @@ -175,9 +175,9 @@ [[package]] name = "clap" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", "clap_derive", @@ -185,9 +185,9 @@ [[package]] name = "clap_builder" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstream", "anstyle", @@ -197,9 +197,9 @@ [[package]] name = "clap_derive" -version = "4.6.4" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061" +checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0" dependencies = [ "heck", "proc-macro2", @@ -301,9 +301,9 @@ [[package]] name = "either" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" +checksum = "252afb9ae5eaa683babdc6a068b3f5726eb19e05070c731f9b2a23a7c3e8ed34" [[package]] name = "encode_unicode" @@ -345,9 +345,9 @@ [[package]] name = "find-msvc-tools" -version = "0.1.11" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" +checksum = "ef25905e51abafe4dcea6c15fec58c57b601cdbd0ee53d22ea1d3016c587d39b" [[package]] name = "fixedbitset" @@ -612,9 +612,9 @@ [[package]] name = "log" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" +checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6" [[package]] name = "memchr" @@ -624,7 +624,7 @@ [[package]] name = "mergiraf" -version = "0.19.1" +version = "0.20.0" dependencies = [ "assert_cmd", "caplog", @@ -682,6 +682,7 @@ "tree-sitter-php", "tree-sitter-properties", "tree-sitter-python-orchard", + "tree-sitter-qmljs", "tree-sitter-r", "tree-sitter-requirements", "tree-sitter-ruby", @@ -936,18 +937,18 @@ [[package]] name = "rstest" -version = "0.26.1" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5a3193c063baaa2a95a33f03035c8a72b83d97a54916055ba22d35ed3839d49" +checksum = "948203e6d13b83e51a90d7cf236dd58a0065f23f4b902f00f306e7eb2bd09b9c" dependencies = [ "rstest_macros", ] [[package]] name = "rstest_macros" -version = "0.26.1" +version = "0.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c845311f0ff7951c5506121a9ad75aec44d083c31583b2ea5a30bcb0b0abba0" +checksum = "a8d92eaf7b6e51e12471d71ddc72608e7151573de44099aacfbb1128177c0da4" dependencies = [ "cfg-if", "glob", @@ -1211,9 +1212,9 @@ [[package]] name = "tree-sitter" -version = "0.26.12" +version = "0.26.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83c567a8e18ae93f20982c90370b16fd24023aeaf52f6052b96957ab253a0fec" +checksum = "17ebdd3a5a7e28a1890b876fdbd0c3c0fe0a6336cffaa104f11b9f720c9daa29" dependencies = [ "cc", "regex", @@ -1255,9 +1256,9 @@ [[package]] name = "tree-sitter-cmake" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164e0c4f4236ec5ceff14824a5528615cf462e100467e49826442ff57d327061" +checksum = "d22893fac54133fdb93497efc45713d53a96d93b035288c7a8ab0c2af77c0ddd" dependencies = [ "cc", "tree-sitter-language", @@ -1275,9 +1276,9 @@ [[package]] name = "tree-sitter-dart-orchard" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e9e47f28354ae26b1ecfe2b2baa157e5145665d78838fe189008e921c0971eb" +checksum = "a1a1fa2972c59e6f9c9529220baef8ec7c08246df12226d6a2562708a302cd59" dependencies = [ "cc", "tree-sitter-language", @@ -1405,9 +1406,9 @@ [[package]] name = "tree-sitter-java-orchard" -version = "0.5.15" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d653f4d9f16496ec19de6bcb7b7688d3f6b203c9c0af979bd5294fc058a3e16f" +checksum = "7ab98a9ff17dc2fe04524bdf11abb8eb4da7252de249e65deb5dede10a953a5f" dependencies = [ "cc", "tree-sitter-language", @@ -1471,9 +1472,9 @@ [[package]] name = "tree-sitter-matlab" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d8831a78547f54860dd8467166b1ab0c466d03d43c4bb447af55c024281f7" +checksum = "97962a0daf32492453fbea1984d34c4d8460b66b95c6c04feecc4cbf1b00a984" dependencies = [ "cc", "tree-sitter-language", @@ -1501,9 +1502,9 @@ [[package]] name = "tree-sitter-ocaml" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b943275476bac8f73e08bc4050e21d89d61ff68e1751b789ba74917b9147a85" +checksum = "43adb10fcccbcbbce0f4adc9dab7cd55f0a5eafc2d71bd4c03fcc5d6767066e0" dependencies = [ "cc", "tree-sitter-language", @@ -1540,6 +1541,16 @@ ] [[package]] +name = "tree-sitter-qmljs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67445ea937cd7eadaf2f628e2e7dd234374586cc31b4d1d63dbb5f5e7f9d9b62" +dependencies = [ + "cc", + "tree-sitter-language", +] + +[[package]] name = "tree-sitter-r" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" @@ -1571,9 +1582,9 @@ [[package]] name = "tree-sitter-rust-orchard" -version = "0.16.8" +version = "0.16.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ef7e314bea5898ba33a1018251f0c5330e812fe71f5950f874ffcd85ab1ff10" +checksum = "ae59062ce889b2581ac33361c6a3799673c7496aafa64dd958ba0268c00e014f" dependencies = [ "cc", "tree-sitter-language", @@ -1621,9 +1632,9 @@ [[package]] name = "tree-sitter-systemverilog" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc40d99fa6fb0a24b9eb62082b5667d40359b5da175d17d44052b3b1bf9dcca9" +checksum = "7d9f02d7fd20691acb5edf44a782f0b9fa278d9987befb1ae597c768707b95e6" dependencies = [ "cc", "tree-sitter-language", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/Cargo.toml new/mergiraf-0.20.0/Cargo.toml --- old/mergiraf-0.19.1/Cargo.toml 2026-09-01 10:50:21.000000000 +0200 +++ new/mergiraf-0.20.0/Cargo.toml 2026-09-26 11:02:58.000000000 +0200 @@ -11,7 +11,7 @@ [package] name = "mergiraf" -version = "0.19.1" +version = "0.20.0" edition = "2024" license = "GPL-3.0-only" repository = "https://codeberg.org/mergiraf/mergiraf" @@ -28,7 +28,7 @@ [dependencies] tree-sitter = "0.26" -tree-sitter-ocaml = "0.25" +tree-sitter-ocaml = "0.26" tree-sitter-rust-orchard = "0.16" tree-sitter-json = "0.24" tree-sitter-yaml = "0.7" @@ -44,7 +44,7 @@ tree-sitter-go = "0.25" tree-sitter-gomod-orchard = "0.5" tree-sitter-gosum-orchard = "0.3" -tree-sitter-dart-orchard = "0.6" +tree-sitter-dart-orchard = "0.7" tree-sitter-typescript = "0.23" tree-sitter-python-orchard = "0.4" tree-sitter-php = "0.24" @@ -62,6 +62,7 @@ tree-sitter-gleam = "1.0.0" tree-sitter-erlang = "0.20.0" tree-sitter-matlab = "1.3.0" +tree-sitter-qmljs = "0.3.0" regex = "1.12" itertools = "0.15" tree-sitter-nix = "0.3" @@ -98,7 +99,7 @@ [dev-dependencies] caplog = "0.3" -rstest = { version = "0.26", default-features = false } +rstest = { version = "0.27", default-features = false } tempfile = "3" insta = { version = "1.43", default-features = false, features = ["colors"] } pretty_assertions = "1.4.1" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/build.rs new/mergiraf-0.20.0/build.rs --- old/mergiraf-0.19.1/build.rs 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/build.rs 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,3 @@ +fn main() { + println!("cargo:rerun-if-changed=tests/data"); +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/doc/src/languages.md new/mergiraf-0.20.0/doc/src/languages.md --- old/mergiraf-0.19.1/doc/src/languages.md 2026-09-01 10:50:21.000000000 +0200 +++ new/mergiraf-0.20.0/doc/src/languages.md 2026-09-26 11:02:58.000000000 +0200 @@ -22,6 +22,7 @@ * OCaml (*.ml, *.mli) * PHP (*.php, *.phmtl) * Python (*.py) +* QML (*.qml) * R (*.R, *.r, .Rprofile) * Ruby (*.rb) * Rust (*.rs) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_enum_values/Base.qml new/mergiraf-0.20.0/examples/qml/working/add_enum_values/Base.qml --- old/mergiraf-0.19.1/examples/qml/working/add_enum_values/Base.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_enum_values/Base.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,5 @@ +import QtQuick 2.15 + +Item { + enum Color { Red } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_enum_values/Expected.qml new/mergiraf-0.20.0/examples/qml/working/add_enum_values/Expected.qml --- old/mergiraf-0.19.1/examples/qml/working/add_enum_values/Expected.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_enum_values/Expected.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,11 @@ +import QtQuick 2.15 + +Item { +<<<<<<< LEFT + enum Color { Red, Green } +||||||| BASE + enum Color { Red } +======= + enum Color { Red, Blue } +>>>>>>> RIGHT +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_enum_values/Left.qml new/mergiraf-0.20.0/examples/qml/working/add_enum_values/Left.qml --- old/mergiraf-0.19.1/examples/qml/working/add_enum_values/Left.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_enum_values/Left.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,5 @@ +import QtQuick 2.15 + +Item { + enum Color { Red, Green } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_enum_values/Right.qml new/mergiraf-0.20.0/examples/qml/working/add_enum_values/Right.qml --- old/mergiraf-0.19.1/examples/qml/working/add_enum_values/Right.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_enum_values/Right.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,5 @@ +import QtQuick 2.15 + +Item { + enum Color { Red, Blue } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_functions/Base.qml new/mergiraf-0.20.0/examples/qml/working/add_functions/Base.qml --- old/mergiraf-0.19.1/examples/qml/working/add_functions/Base.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_functions/Base.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,5 @@ +import QtQuick 2.15 + +Rectangle { + function f() { return 1; } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_functions/Expected.qml new/mergiraf-0.20.0/examples/qml/working/add_functions/Expected.qml --- old/mergiraf-0.19.1/examples/qml/working/add_functions/Expected.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_functions/Expected.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,8 @@ +import QtQuick 2.15 + +Rectangle { + function f() { return 1; } + function g() { return 2; } + + function h() { return 3; } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_functions/Left.qml new/mergiraf-0.20.0/examples/qml/working/add_functions/Left.qml --- old/mergiraf-0.19.1/examples/qml/working/add_functions/Left.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_functions/Left.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,6 @@ +import QtQuick 2.15 + +Rectangle { + function f() { return 1; } + function g() { return 2; } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_functions/Right.qml new/mergiraf-0.20.0/examples/qml/working/add_functions/Right.qml --- old/mergiraf-0.19.1/examples/qml/working/add_functions/Right.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_functions/Right.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,6 @@ +import QtQuick 2.15 + +Rectangle { + function f() { return 1; } + function h() { return 3; } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_imports/Base.qml new/mergiraf-0.20.0/examples/qml/working/add_imports/Base.qml --- old/mergiraf-0.19.1/examples/qml/working/add_imports/Base.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_imports/Base.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,5 @@ +import QtQuick 2.15 + +Rectangle { + width: 640 +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_imports/Expected.qml new/mergiraf-0.20.0/examples/qml/working/add_imports/Expected.qml --- old/mergiraf-0.19.1/examples/qml/working/add_imports/Expected.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_imports/Expected.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,7 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 +import QtQuick.Layouts 1.15 + +Rectangle { + width: 640 +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_imports/Left.qml new/mergiraf-0.20.0/examples/qml/working/add_imports/Left.qml --- old/mergiraf-0.19.1/examples/qml/working/add_imports/Left.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_imports/Left.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,6 @@ +import QtQuick 2.15 +import QtQuick.Controls 2.15 + +Rectangle { + width: 640 +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_imports/Right.qml new/mergiraf-0.20.0/examples/qml/working/add_imports/Right.qml --- old/mergiraf-0.19.1/examples/qml/working/add_imports/Right.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_imports/Right.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,6 @@ +import QtQuick 2.15 +import QtQuick.Layouts 1.15 + +Rectangle { + width: 640 +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_properties/Base.qml new/mergiraf-0.20.0/examples/qml/working/add_properties/Base.qml --- old/mergiraf-0.19.1/examples/qml/working/add_properties/Base.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_properties/Base.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,6 @@ +import QtQuick 2.15 + +Rectangle { + width: 640 + height: 480 +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_properties/Expected.qml new/mergiraf-0.20.0/examples/qml/working/add_properties/Expected.qml --- old/mergiraf-0.19.1/examples/qml/working/add_properties/Expected.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_properties/Expected.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,9 @@ +import QtQuick 2.15 + +Rectangle { + width: 640 + height: 480 + property int counter: 0 + + property string title: "Hello" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_properties/Left.qml new/mergiraf-0.20.0/examples/qml/working/add_properties/Left.qml --- old/mergiraf-0.19.1/examples/qml/working/add_properties/Left.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_properties/Left.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,7 @@ +import QtQuick 2.15 + +Rectangle { + width: 640 + height: 480 + property int counter: 0 +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/examples/qml/working/add_properties/Right.qml new/mergiraf-0.20.0/examples/qml/working/add_properties/Right.qml --- old/mergiraf-0.19.1/examples/qml/working/add_properties/Right.qml 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/examples/qml/working/add_properties/Right.qml 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,7 @@ +import QtQuick 2.15 + +Rectangle { + width: 640 + height: 480 + property string title: "Hello" +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/helpers/benchmark.sh new/mergiraf-0.20.0/helpers/benchmark.sh --- old/mergiraf-0.19.1/helpers/benchmark.sh 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/helpers/benchmark.sh 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,73 @@ +#!/usr/bin/env bash + +if [ "$#" -ne 2 ]; then + echo "usage: $0 <path> <executable>" + echo "where <path> is a path to a directory containing test cases, such as examples/java/working," + echo "and <executable> is a path to a mergiraf binary to benchmark." + echo "This prints a TSV file summarizing benchmarking results on the standard output." + echo "It can then be used with helpers/summarize_benchmark.py to get statistics in Markdown." + exit 1 +fi + +suite=$1 +executable=$2 + +script_path="$(realpath "${BASH_SOURCE[0]}")" +script_dir="$(dirname "${script_path}")" + +tmp_dir=/tmp/tmp$$ +mkdir -p $tmp_dir + +# Print TSV headers +echo -e "status\ttiming\tlanguage\tcase" + +# For each test case… + +find -L "$suite" -type d | while read -r testid ; do + # Detect its language + ext=$(ls "$testid" | grep Base | sed -e 's/Base//') + if [ ! -e "$testid/Expected$ext" ]; then + continue + fi + + language="*$ext" + extra_args="" + if [ -e "$testid/language" ]; then + language=$(cat "$testid/language") + extra_args="$extra_args --language $language" + fi + + # Run the executable to benchmark + /usr/bin/env time -o $tmp_dir/timings -f "%e" "$executable" merge -v "$testid/Base$ext" "$testid/Left$ext" "$testid/Right$ext" -s BASE -x LEFT -y RIGHT $extra_args > "$tmp_dir/our_merge_raw$ext" 2> $tmp_dir/mergiraf_log + retcode=$? + + # Normalize line endings both for the expected value and our output + sed -e '$a\' "$tmp_dir/our_merge_raw$ext" > "$tmp_dir/our_merge$ext" + sed -e '$a\' "$testid/Expected$ext" > "$tmp_dir/expected_merge$ext" + + timing=$(tail -1 $tmp_dir/timings) + + # Categorize the test outcome + if [ $retcode -ge 128 ]; then + outcome="Panic" + elif diff -B "$tmp_dir/our_merge$ext" "$tmp_dir/expected_merge$ext" > /dev/null 2>&1; then + outcome="Exact" + else + conflict_count=$(grep -c "<<<<<<<" "$tmp_dir/our_merge_raw$ext") + if [ "$conflict_count" -ge 1 ]; then + # Check that we were able to parse the files correctly + if grep "encountered an error: parse error at " $tmp_dir/mergiraf_log > /dev/null; then + outcome="Parse" + else + outcome="Conflict" + fi + elif cargo compare --commutative "$tmp_dir/our_merge$ext" "$tmp_dir/expected_merge$ext" > /dev/null 2>&1; then + outcome="Format" + else + outcome="Differ" + fi; + fi; + echo -e "${outcome}\t${timing}\t${language}\t${testid}" +done; + +rm -rf ${tmp_dir} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/helpers/summarize_benchmark.py new/mergiraf-0.20.0/helpers/summarize_benchmark.py --- old/mergiraf-0.19.1/helpers/summarize_benchmark.py 1970-01-01 01:00:00.000000000 +0100 +++ new/mergiraf-0.20.0/helpers/summarize_benchmark.py 2026-09-26 11:02:58.000000000 +0200 @@ -0,0 +1,219 @@ +#!/usr/bin/env python3 +import sys +import csv +import math +from collections import defaultdict +from typing import Any, Optional, Self + +""" +Utility that summarizes the outcomes of a benchmark run with the `helpers/benchmark.sh` script. +When supplied with the path to a single benchmark TSV log, it gives statistics about how many +test cases ended up in different categories, as a Markdown table. +When supplied with two such paths, it generates +- a comparison between the logs, as a similar table +- a confusion matrix indicating from which status to which status test cases changed +""" + +# The order in which test case categories should be presented +# Roughly from "best to worst", so that the confusion matrix +# can be intuitively interpreted as satisfying if it is lower-triangular +STATUS_ORDER = ["Exact", "Format", "Conflict", "Differ", "Parse", "Panic"] + +STATUS = "status" # aka `outcome` +TIMING = "timing" +LANGUAGE = "language" +CASE = "case" # aka `test_id` + + +class TimingStats: + """ + Utility to compute an average out of many data points. + We could also compute the standard deviation by computing the sum of squares. + """ + + def __init__(self): + self.count = 0 + self.sum = 0 + + def add(self, timing: int): + self.count += 1 + self.sum += timing + + def average(self): + return float(self.sum) / self.count + + +class StatsLine: + """ + Statistics about how many test cases land in each status category, + and how long they took. + """ + + def __init__(self): + self.timing = TimingStats() + self.states = defaultdict(int) + + def add(self, case: dict[str, Any]): + timing = float(case[TIMING]) + self.timing.add(timing) + status = case[STATUS] + self.states[status] += 1 + + def to_markdown(self): + cases = self.timing.count + parts = [f"{cases:,}"] + for status in STATUS_ORDER: + count = self.states[status] + if count: + parts.append(f"{count:,} ({100 * count / cases:.0f}%)") + else: + parts.append("0") + + timing = self.timing.average() + parts.append(f"{timing:.3f}") + return "| " + (" | ".join(parts)) + " |" + + +class StatsDiff: + """ + Difference between two `StatsLine` from two different benchmark runs + """ + + def __init__(self, first: StatsLine, second: StatsLine): + self.first = first + self.second = second + + def to_markdown(self): + timing = self.second.timing.average() + timing_diff = timing - self.first.timing.average() + parts = [f"{self.second.timing.count:,}"] + for status in STATUS_ORDER: + first = self.first.states[status] + second = self.second.states[status] + if second - first and self.first.timing.count: + percent_change = 100 * (second - first) / self.first.timing.count + parts.append(f"{second - first:+,} **({percent_change:+.1f}%)**") + else: + parts.append(f"{second - first:+,}") + + if math.fabs(timing_diff) > 0.001: + if timing > 0: + percent_change = 100 * timing_diff / self.first.timing.average() + parts.append(f"{timing_diff:+.3f} ({percent_change:+.1f}%)") + else: + parts.append(f"{timing_diff:+.3f})") + else: + parts.append(f"{timing:.3f} (+0)") + return "| " + (" | ".join(parts)) + " |" + + +class BenchmarkLog: + def __init__(self, path: str, restrict_to: Optional[Self] = None): + """ + Parses a benchmark log as a TSV file, + returning global and per-language statistics. + If another BenchmarkLog is passed as `restrict_to`, + then only cases which are also covered by the other + log are taken into account. + """ + self.global_stats = StatsLine() + self.per_language: defaultdict[str, StatsLine] = defaultdict(StatsLine) + self.case_to_status: dict[str, str] = {} + with open(path, "r") as f: + csv_reader = csv.DictReader(f, delimiter="\t") + for case in csv_reader: + if restrict_to is None or case[CASE] in restrict_to.case_to_status: + self.global_stats.add(case) + self.per_language[case[LANGUAGE]].add(case) + self.case_to_status[case[CASE]] = case[STATUS] + + +def print_header(): + """ + Prints the header of a Markdown table representing test case categories + """ + # fmt: off + print("| Language | Cases | " + " | ".join(STATUS_ORDER) + " | Time (s) |") + print("| -------- | ----- | " + " | ".join(("-" * len(status) for status in STATUS_ORDER)) + " | -------- |") + # fmt: on + + +def summarize_benchmark_log(path: str): + """ + Prints a summary of a single benchmark + """ + print_header() + log = BenchmarkLog(path) + lang_stats = list(log.per_language.items()) + lang_stats.sort(key=lambda pair: -pair[1].timing.count) + for lang, stats in lang_stats: + print(f"| `{lang}` {stats.to_markdown()}") + + if len(log.per_language) > 1: + print(f"| **Total** {log.global_stats.to_markdown()}") + + +def compare_benchmark_logs(path_before: str, path_after: str): + """ + Prints a summary of the differences between two benchmark runs + """ + print_header() + after_log = BenchmarkLog(path_after) + before_log = BenchmarkLog(path_before, restrict_to=after_log) + after_lang_stats = list(after_log.per_language.items()) + after_lang_stats.sort(key=lambda pair: -pair[1].timing.count) + for lang, stats in after_lang_stats: + diff = StatsDiff(before_log.per_language[lang], stats) + print(f"| `{lang}` {diff.to_markdown()}") + + if len(after_log.per_language) > 1: + global_diff = StatsDiff(before_log.global_stats, after_log.global_stats) + print(f"| **Total** {global_diff.to_markdown()}") + + print("") + + confusion_matrix = defaultdict(set) + for case, status in after_log.case_to_status.items(): + previous_status = before_log.case_to_status.get(case) + if not previous_status: + print( + f"warning: case not found in previous benchmark: {case}", + file=sys.stderr, + ) + else: + confusion_matrix[(previous_status, status)].add(case) + + # fmt: off + print("| ↓ Before \\ After → | " + " | ".join(STATUS_ORDER) + " |") + print("| ------------------ | " + " | ".join(["-" * len(status) for status in STATUS_ORDER]) + " |") + # fmt: on + + for status in STATUS_ORDER: + row = [] + for new_status in STATUS_ORDER: + cell = "" + if confusion_matrix[(status, new_status)]: + cell = f"{len(confusion_matrix[(status, new_status)]):,}" + if cell and status != new_status: + cell = f"**{cell}**" + row.append(cell) + print("| " + status + " | " + " | ".join(row) + " |") + + print("") + print("## Suspicious status changes") + print("") + for index, status in enumerate(STATUS_ORDER): + for new_status in STATUS_ORDER[(index + 1) :]: + cases = confusion_matrix[(status, new_status)] + if cases: + print(f"### {status} → {new_status}") + for case in cases: + print(case) + print("") + + +if __name__ == "__main__": + if len(sys.argv) == 3: + compare_benchmark_logs(sys.argv[1], sys.argv[2]) + else: + summarize_benchmark_log(sys.argv[1]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/mgf_dev/src/main.rs new/mergiraf-0.20.0/mgf_dev/src/main.rs --- old/mergiraf-0.19.1/mgf_dev/src/main.rs 2026-09-01 10:50:21.000000000 +0200 +++ new/mergiraf-0.20.0/mgf_dev/src/main.rs 2026-09-26 11:02:58.000000000 +0200 @@ -25,6 +25,9 @@ /// Override automatic language detection. #[arg(short = 'L', long, global = true)] language: Option<String>, + /// Be verbose + #[arg(short = 'v', long, global = true)] + verbose: bool, } #[derive(Subcommand, Debug)] @@ -76,9 +79,16 @@ } fn main() { - stderrlog::new().module(module_path!()).init().unwrap(); + let args = CliArgs::parse(); + stderrlog::new() + // most (currently, all) logging statements are made in the `mergiraf` crate, + // so initialize the logger there as well + .modules([module_path!(), "mergiraf"]) + .verbosity(if args.verbose { 3 } else { 2 }) + .init() + .unwrap(); - match real_main(&CliArgs::parse()) { + match real_main(&args) { Ok(exit_code) => exit(exit_code), Err(error) => { eprintln!("mgf_dev: {error}"); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/src/ast.rs new/mergiraf-0.20.0/src/ast.rs --- old/mergiraf-0.19.1/src/ast.rs 2026-09-01 10:50:21.000000000 +0200 +++ new/mergiraf-0.20.0/src/ast.rs 2026-09-26 11:02:58.000000000 +0200 @@ -102,6 +102,22 @@ pub lang_profile: &'a LangProfile, } +/// A cache of compiled Tree-sitter queries. This avoids needing to re-compile the same query for +/// every recursive injection (e.g. every Rust macro invocation). +#[derive(Default)] +struct QueryCache(FxHashMap<(&'static str, &'static str), Query>); + +impl QueryCache { + fn get(&mut self, lang_profile: &LangProfile, query_str: &'static str, kind: &str) -> &Query { + self.0 + .entry((lang_profile.name, query_str)) + .or_insert_with(|| { + Query::new(&lang_profile.language, query_str) + .unwrap_or_else(|err| panic!("Invalid {kind} query: {err}")) + }) + } +} + impl<'a> AstNode<'a> { /// Parse a string to a tree using the language supplied pub fn parse( @@ -111,7 +127,15 @@ ref_arena: &'a Arena<&'a Self>, ) -> Result<&'a Self, ParsingError> { let mut next_node_id = 1; - let root = Self::parse_root(source, None, lang_profile, arena, &mut next_node_id)?; + let mut query_cache = QueryCache::default(); + let root = Self::parse_root( + source, + None, + lang_profile, + arena, + &mut next_node_id, + &mut query_cache, + )?; root.internal_precompute_root_dfs(ref_arena); Ok(root) } @@ -125,6 +149,7 @@ lang_profile: &'a LangProfile, arena: &'a Arena<Self>, next_node_id: &mut usize, + query_cache: &mut QueryCache, ) -> Result<&'a Self, ParsingError> { let mut parser = Parser::new(); parser @@ -139,9 +164,10 @@ let tree = parser .parse(source, None) .expect("Parsing source code failed"); - let node_id_to_injection_lang = Self::locate_injections(&tree, source, lang_profile); + let node_id_to_injection_lang = + Self::locate_injections(&tree, source, lang_profile, query_cache); let node_id_to_commutative_parent = - Self::locate_commutative_parents_by_query(&tree, source, lang_profile); + Self::locate_commutative_parents_by_query(&tree, source, lang_profile, query_cache); let range_for_root = if let Some(range) = range { range.start_byte..range.end_byte } else { @@ -153,6 +179,7 @@ lang_profile, arena, next_node_id, + query_cache, &node_id_to_injection_lang, &node_id_to_commutative_parent, Some(range_for_root), @@ -165,19 +192,19 @@ tree: &Tree, source: &'a str, lang_profile: &'b LangProfile, + query_cache: &mut QueryCache, ) -> FxHashMap<usize, &'b CommutativeParent> { let mut node_id_to_commutative_parent = FxHashMap::default(); // For each commutative parent that is defined by a tree-sitter query for commutative_parent in &lang_profile.commutative_parents { if let ParentType::ByQuery(query_str) = commutative_parent.parent_type() { // Execute this query over the tree - let query = Query::new(&lang_profile.language, query_str) - .expect("Invalid commutative parent query"); + let query = query_cache.get(lang_profile, query_str, "commutative parent"); let commutative_capture_index = query .capture_index_for_name("commutative") .expect("Commutative parent query without a '@commutative' capture"); let mut cursor = QueryCursor::new(); - let matches = cursor.matches(&query, tree.root_node(), source.as_bytes()); + let matches = cursor.matches(query, tree.root_node(), source.as_bytes()); // For each match, mark the captured node(s) as commutative matches.for_each(|m| { node_id_to_commutative_parent.extend( @@ -195,12 +222,13 @@ tree: &Tree, source: &'a str, lang_profile: &'a LangProfile, + query_cache: &mut QueryCache, ) -> FxHashMap<usize, &'static LangProfile> { let Some(query_str) = lang_profile.injections else { return FxHashMap::default(); }; let mut node_id_to_injection_lang = FxHashMap::default(); - let query = Query::new(&lang_profile.language, query_str).expect("Invalid injection query"); + let query = query_cache.get(lang_profile, query_str, "injection"); let content_capture_index = query .capture_index_for_name("injection.content") .expect("Injection query without an injection.content capture"); @@ -208,7 +236,7 @@ // or statically defined as a property (fixed by the injection query), in which case the capture below won't be defined. let language_capture_index = query.capture_index_for_name("injection.language"); let mut cursor = QueryCursor::new(); - let matches = cursor.matches(&query, tree.root_node(), source.as_bytes()); + let matches = cursor.matches(query, tree.root_node(), source.as_bytes()); matches.for_each(|m| { let pattern_properties = query.property_settings(m.pattern_index); // first, check if the language is statically defined in this clause of the query as a property @@ -247,6 +275,7 @@ lang_profile: &'a LangProfile, arena: &'a Arena<Self>, next_node_id: &mut usize, + query_cache: &mut QueryCache, node_id_to_injection_lang: &FxHashMap<usize, &'static LangProfile>, node_id_to_commutative_parent: &FxHashMap<usize, &'a CommutativeParent>, range_for_root: Option<Range<usize>>, @@ -271,6 +300,7 @@ injection_lang, arena, next_node_id, + query_cache, ) { children.push(injected_root); last_child_end = injected_root.byte_range.end; @@ -284,6 +314,7 @@ lang_profile, arena, next_node_id, + query_cache, node_id_to_injection_lang, node_id_to_commutative_parent, None, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/src/lang_profile.rs new/mergiraf-0.20.0/src/lang_profile.rs --- old/mergiraf-0.19.1/src/lang_profile.rs 2026-09-01 10:50:21.000000000 +0200 +++ new/mergiraf-0.20.0/src/lang_profile.rs 2026-09-26 11:02:58.000000000 +0200 @@ -353,7 +353,7 @@ } /// the type of the root node - pub(crate) fn parent_type(&self) -> &ParentType<'_> { + pub(crate) fn parent_type(&self) -> &ParentType<'static> { &self.parent_type } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/src/merge.rs new/mergiraf-0.20.0/src/merge.rs --- old/mergiraf-0.19.1/src/merge.rs 2026-09-01 10:50:21.000000000 +0200 +++ new/mergiraf-0.20.0/src/merge.rs 2026-09-26 11:02:58.000000000 +0200 @@ -80,6 +80,7 @@ Arc::clone(&contents_base), Arc::clone(&contents_left), Arc::clone(&contents_right), + fname_base, lang_profile, settings, full_merge, @@ -125,6 +126,7 @@ contents_base: Arc<Cow<'static, str>>, contents_left: Arc<Cow<'static, str>>, contents_right: Arc<Cow<'static, str>>, + fname_base: &Path, lang_profile: Arc<Cow<'static, LangProfile>>, settings: DisplaySettings<'static>, full_merge: bool, @@ -197,7 +199,10 @@ match rx.recv_timeout(timeout) { Ok(merges) => merges, Err(oneshot::RecvTimeoutError::Timeout) => { - warn!("structured merge took too long, falling back to Git"); + warn!( + "structured merge of '{}' took too long, falling back to Git", + fname_base.display() + ); vec![] } Err(oneshot::RecvTimeoutError::Disconnected) => unreachable!(), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/src/supported_langs.rs new/mergiraf-0.20.0/src/supported_langs.rs --- old/mergiraf-0.19.1/src/supported_langs.rs 2026-09-01 10:50:21.000000000 +0200 +++ new/mergiraf-0.20.0/src/supported_langs.rs 2026-09-26 11:02:58.000000000 +0200 @@ -1577,6 +1577,50 @@ extra_comment_nodes: &[], allow_parse_errors: false, }, + LangProfile { + name: "qml", + alternate_names: &[], + extensions: &["qml"], + file_names: &[], + language: tree_sitter_qmljs::LANGUAGE.into(), + commutative_parents: vec![ + // QML import statements are unordered + CommutativeParent::without_delimiters("program", "\n") + .restricted_to_groups(&[&["ui_import"]]), + CommutativeParent::new("ui_object_initializer", " {\n", "\n\n", "\n}\n") + .restricted_to(vec![ + // Most things in qml bodies are globally accessible within the module. + ChildrenGroup::with_separator(&["ui_binding"], "\n"), + ChildrenGroup::with_separator(&["ui_property"], "\n\n"), + ChildrenGroup::with_separator( + &["function_declaration", "generator_function_declaration"], + "\n\n", + ), + ChildrenGroup::with_separator(&["ui_signal"], "\n\n"), + ChildrenGroup::with_separator(&["enum_declaration"], "\n\n"), + ]), + ], + signatures: vec![ + // UI Imports should be unique (don't import the same thing twice) + signature("ui_import", vec![vec![]]), + // Bindings, properties, and function names, signals, and enums are also unique within they're scope + signature("ui_binding", vec![vec![Field("name")]]), + signature("ui_property", vec![vec![Field("name")]]), + signature("function_declaration", vec![vec![Field("name")]]), + signature("generator_function_declaration", vec![vec![Field("name")]]), + signature("ui_signal", vec![vec![Field("name")]]), + signature( + "variable_declaration", + vec![vec![ChildKind("variable_declarator"), Field("name")]], + ), + signature("enum_declaration", vec![vec![Field("name")]]), + ], + atomic_nodes: &[], + injections: None, + flattened_nodes: &[], + extra_comment_nodes: &[], + allow_parse_errors: false, + }, ] }); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/mergiraf-0.19.1/tests/timeout_support.rs new/mergiraf-0.20.0/tests/timeout_support.rs --- old/mergiraf-0.19.1/tests/timeout_support.rs 2026-09-01 10:50:21.000000000 +0200 +++ new/mergiraf-0.20.0/tests/timeout_support.rs 2026-09-26 11:02:58.000000000 +0200 @@ -1,3 +1,4 @@ +use assert_cmd::prelude::*; use diffy_imara::{PatchFormatter, create_patch}; mod common; @@ -28,3 +29,18 @@ panic!(); } } + +/// The timeout warning should name the file which fell back to Git +#[test] +fn timeout_warning_names_the_file() { + merge() + .arg("tests/data/java/working/move_and_modify_conflict/Base.java") + .arg("tests/data/java/working/move_and_modify_conflict/Left.java") + .arg("tests/data/java/working/move_and_modify_conflict/Right.java") + .arg("--path-name=src/main/java/Example.java") + .arg("--timeout=1") + .assert() + .stderr( + "WARN structured merge of 'src/main/java/Example.java' took too long, falling back to Git\n", + ); +} ++++++ mergiraf.obsinfo ++++++ --- /var/tmp/diff_new_pack.qp6Fkw/_old 2026-09-28 10:46:31.223122869 +0200 +++ /var/tmp/diff_new_pack.qp6Fkw/_new 2026-09-28 10:46:31.232123246 +0200 @@ -1,5 +1,5 @@ name: mergiraf -version: 0.19.1 -mtime: 1788252621 -commit: e1c6514fb364faca51132be2b336aa739cdfadb9 +version: 0.20.0 +mtime: 1790413378 +commit: 182d26ea63aa62f7f5dc213cf8ceb70d83e7750e ++++++ vendor.tar.zst ++++++ /work/SRC/openSUSE:Factory/mergiraf/vendor.tar.zst /work/SRC/openSUSE:Factory/.mergiraf.new.383539/vendor.tar.zst differ: char 7, line 1
