From 1decf691bb0477262c79cccb87f6d153f592888f Mon Sep 17 00:00:00 2001 From: Steven Engler Date: Sun, 4 Feb 2024 16:55:37 -0500 Subject: [PATCH] Initial version '0.1.0' --- Cargo.lock | 652 ++++++++++++++++++++++++++++++++++ Cargo.toml | 16 + README.md | 76 ++++ docs/assets/example-dark.png | Bin 0 -> 64715 bytes docs/assets/example-light.png | Bin 0 -> 67746 bytes docs/publishing.md | 40 +++ src/cli.rs | 72 ++++ src/main.rs | 418 +++++++++++++++++++++- src/parse.rs | 38 ++ src/ui.rs | 389 ++++++++++++++++++++ src/util.rs | 513 ++++++++++++++++++++++++++ 11 files changed, 2213 insertions(+), 1 deletion(-) create mode 100644 README.md create mode 100644 docs/assets/example-dark.png create mode 100644 docs/assets/example-light.png create mode 100644 docs/publishing.md create mode 100644 src/cli.rs create mode 100644 src/parse.rs create mode 100644 src/ui.rs create mode 100644 src/util.rs diff --git a/Cargo.lock b/Cargo.lock index c70c216..e8258fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,658 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2faccea4cc4ab4a667ce676a30e8ec13922a692c99bb8f5b11f1502c72e04220" + +[[package]] +name = "anstyle-parse" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + +[[package]] +name = "bstr" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e578d6ec4194633722ccf9544794b71b1385c3c027efe0c55db226fc880865c" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4df4df40ec50c46000231c914968278b1eb05098cf8f1b3a518a95030e71d1c7" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_derive" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colorchoice" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "diffy" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e616e59155c92257e84970156f506287853355f58cd4a6eb167385722c32b790" +dependencies = [ + "nu-ansi-term", +] + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "encoding_rs_io" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cc3c5651fb62ab8aa3103998dade57efdd028544bd300516baa31840c252a83" +dependencies = [ + "encoding_rs", +] + +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "globset" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57da3b9b5b85bd66f31093f8c408b90a74431672542466497dcbdfdc02034be1" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "grep-matcher" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47a3141a10a43acfedc7c98a60a834d7ba00dfe7bec9071cbfc19b55b292ac02" +dependencies = [ + "memchr", +] + +[[package]] +name = "grep-regex" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f748bb135ca835da5cbc67ca0e6955f968db9c5df74ca4f56b18e1ddbc68230d" +dependencies = [ + "bstr", + "grep-matcher", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "grep-searcher" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba536ae4f69bec62d8839584dd3153d3028ef31bb229f04e09fb5a9e5a193c54" +dependencies = [ + "bstr", + "encoding_rs", + "encoding_rs_io", + "grep-matcher", + "log", + "memchr", + "memmap2", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "ignore" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b46810df39e66e925525d6e38ce1e7f6e1d208f72dc39757880fcb66e2c58af1" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "libc" +version = "0.2.153" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" + +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" + +[[package]] +name = "memmap2" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe751422e4a8caa417e13c3ea66452215d7d63e19e604f4980461212f3ae1322" +dependencies = [ + "libc", +] + +[[package]] +name = "nu-ansi-term" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" +dependencies = [ + "overload", + "winapi", +] + +[[package]] +name = "overload" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" + +[[package]] +name = "proc-macro2" +version = "1.0.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex-automata" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + [[package]] name = "repatch" version = "0.1.0" +dependencies = [ + "anstyle", + "anyhow", + "bstr", + "clap", + "diffy", + "grep-matcher", + "grep-regex", + "grep-searcher", + "ignore", + "libc", + "tempfile", +] + +[[package]] +name = "rustix" +version = "0.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "syn" +version = "2.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" diff --git a/Cargo.toml b/Cargo.toml index 60affe2..f5c1b7b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,5 +2,21 @@ name = "repatch" version = "0.1.0" edition = "2021" +license = "MIT" +repository = "https://github.com/stevenengler/repatch" +description = "A regex find-and-replace tool with a `git add --patch`-like interface." +keywords = ["search", "find", "replace", "regex", "patch"] +categories = ["command-line-utilities", "text processing", "filesystem"] [dependencies] +anstyle = "1.0.4" +anyhow = "1.0.79" +bstr = { version = "1.9.0", features = ["unicode"] } +clap = { version = "4.4.16", features = ["derive", "wrap_help"] } +diffy = "0.3.0" +grep-matcher = "0.1.7" +grep-regex = "0.1.12" +grep-searcher = "0.1.13" +ignore = "0.4.22" +libc = "0.2.152" +tempfile = "3.9.0" diff --git a/README.md b/README.md new file mode 100644 index 0000000..af08b72 --- /dev/null +++ b/README.md @@ -0,0 +1,76 @@ +# re:patch + +[![Latest Version]][crates.io] + +re:patch is a line-oriented find-and-replace tool with a [`git add +--patch`][git-add-patch]-like interface. Regular expressions and capture groups +are supported, and re:patch can be used with files and directories. Only Linux +is currently supported. + +> [!WARNING] +> This tool is still in development. While it Works For Me™, it does not yet +> have any tests. It's recommended to only use this in directories that are +> version controlled. + +[crates.io]: https://crates.io/crates/repatch +[Latest Version]: https://img.shields.io/crates/v/repatch.svg +[git-add-patch]: https://git-scm.com/docs/git-add#Documentation/git-add.txt---patch + +### Install + +You can install from source or through crates.io. You must have a recent +[rust/cargo][rust] toolchain installed. + +``` +# install the latest release from crates.io +cargo install repatch + +# install from source +git clone https://github.com/stevenengler/repatch.git +cd repatch && cargo install --path . +``` + +[rust]: https://www.rust-lang.org/tools/install + +### Example + + + + Command-line usage example. + + +### Notes + +Similar to [ripgrep][ripgrep], gitignore rules are respected and hidden +files/directories are ignored. + +The editor used to edit patches can be configured using environment variables +or the git configuration. The search priority is `VISUAL`, `EDITOR`, +`GIT_EDITOR`, and `git config core.editor`. Otherwise vim is used. Like `sudo +-e` the editor value is split by whitespace characters and executed, and is not +interpreted by a shell. + +Patches shown in the terminal will have ANSI escape sequences replaced with +safe versions. + +Like most text editors, files are replaced and not edited in-place. This means +that the file owner or other metadata may change after editing. The new file +will have the same read/write/execute permissions as the original file. You +will also need enough temporary disk space for this second file. For example if +you're editing a 10 GB file, you must have at least 10 GB of disk space free so +that the new file can be written before the original file is deleted. + +Large files (larger than the amount of available memory) are supported as long +as they have a sufficient number of lines. For example a 10 GB file with 10,000 +lines should work fine, but a 10 GB file with a single line might exhaust the +system memory and would not look very nice in the terminal. + +[ripgrep]: https://github.com/BurntSushi/ripgrep + +### Acknowledgements + +Most of the heavy lifting is done by the [ripgrep][ripgrep] family of crates, +[clap][clap], and [diffy][diffy]. + +[clap]: https://docs.rs/clap/latest/clap/ +[diffy]: https://docs.rs/diffy/latest/diffy/ diff --git a/docs/assets/example-dark.png b/docs/assets/example-dark.png new file mode 100644 index 0000000000000000000000000000000000000000..1c3660cd066786db8a00179a0bfeb1ff3a04afa8 GIT binary patch literal 64715 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
    1H6 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⋙opfo<*FdTre0iI7ZKozo>c3)FgBJ?M8L6+} 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 literal 0 HcmV?d00001 diff --git a/docs/publishing.md b/docs/publishing.md new file mode 100644 index 0000000..67ea5bd --- /dev/null +++ b/docs/publishing.md @@ -0,0 +1,40 @@ +# Publishing a new release + +1. Update the code. + + ```bash + # make sure we don't include personal information (such as our + # home directory name) in the release + cd /tmp + + # make sure we don't include any untracked files in the release + git clone git@github.com:stevenengler/repatch.git + cd repatch + + # update the version + vim Cargo.toml + cargo update --package repatch + + # check for errors + git diff + cargo publish --dry-run --allow-dirty + + # add and commit version changes with commit message, for example + # "Updated version to '0.2.1'" + git add --patch + git commit + git push + ``` + +2. After CI tests finish on GitHub, mark it as a new release. + +3. Publish the crate. + + ```bash + # make sure there are no untracked or changed files + git status + + # publish + cargo publish --dry-run + cargo publish + ``` diff --git a/src/cli.rs b/src/cli.rs new file mode 100644 index 0000000..afe0017 --- /dev/null +++ b/src/cli.rs @@ -0,0 +1,72 @@ +use std::path::PathBuf; + +use clap::Parser; + +const VERSION_STR: &str = concat!("re:patch ", env!("CARGO_PKG_VERSION")); + +/// re:patch is a line-oriented find-and-replace tool with a `git add --patch`-like interface. +/// Directories are searched recursively. Hidden files/directories and binary files are ignored, as +/// well as files/directories specified in gitignore rules. Regular expressions with capture groups +/// are supported. +#[derive(Debug, Parser)] +#[command(version, name = "re:patch", max_term_width = 120, help_expected = true)] +#[command(before_help(VERSION_STR))] +pub struct Args { + /// Regex to search for, optionally with capture groups. + pub find: String, + /// Text to replace `` with. Capture group indices and names are supported. + pub replace: String, + /// Paths (files and/or directories) to search recursively. + #[clap(required = true)] + pub paths: Vec, + /// Case-insensitive search. + #[clap(long, short)] + pub ignore_case: bool, + /// Ignore filesystem-related errors while searching ("no such file", "permission denied", etc). + #[clap(long)] + pub ignore_errors: bool, + /// Generate diffs with `` lines of context; also accepts "infinite". + #[clap(long, default_value_t, value_name = "N")] + pub context: Context, + /// Show the changes without modifying any files. + /// + /// This does not generate valid patch files and is meant only for terminal output. ANSI escape + /// sequences are replaced in the generated patches. + #[clap(long, conflicts_with_all(["apply"]))] + pub show: bool, + /// Apply and write all changes automatically without any user input or confirmation. + #[clap(long)] + pub apply: bool, +} + +#[derive(Copy, Clone, Debug)] +pub enum Context { + Num(u64), + Infinite, +} + +impl std::str::FromStr for Context { + type Err = std::num::ParseIntError; + + fn from_str(s: &str) -> Result { + Ok(match s { + "infinite" => Self::Infinite, + x => Self::Num(x.parse()?), + }) + } +} + +impl std::fmt::Display for Context { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Num(x) => write!(f, "{x}"), + Self::Infinite => write!(f, "infinite"), + } + } +} + +impl Default for Context { + fn default() -> Self { + Self::Num(5) + } +} diff --git a/src/main.rs b/src/main.rs index f328e4d..a45ebf8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1 +1,417 @@ -fn main() {} +#![deny(unsafe_op_in_unsafe_fn)] + +mod cli; +mod parse; +mod ui; +mod util; + +use std::collections::BTreeMap; +use std::fs::File; +use std::io::{BufRead, BufReader, BufWriter, Write}; +use std::path::{Path, PathBuf}; +use std::process::ExitCode; +use std::time::SystemTime; + +use anyhow::Context as anyhowContext; +use bstr::ByteSlice; +use clap::Parser; +use grep_regex::{RegexMatcher, RegexMatcherBuilder}; +use grep_searcher::sinks::Bytes; +use grep_searcher::Searcher; +use ignore::WalkBuilder; + +use crate::cli::{Args, Context}; +use crate::ui::{error, style, MenuOption, PatchOption, COUNT_STYLE}; +use crate::util::ReplaceFileError; + +fn main() -> ExitCode { + if let Err(e) = run(Args::parse()) { + error!("{e:#}"); + return ExitCode::FAILURE; + } + + ExitCode::SUCCESS +} + +fn run(args: Args) -> anyhow::Result<()> { + let mut matcher = RegexMatcherBuilder::new(); + matcher.case_insensitive(args.ignore_case); + let matcher = matcher.build(&args.find)?; + + let mut matches = match find_matches(&matcher, &args.paths, args.ignore_errors) { + Ok(x) => x, + Err(num_errors) => anyhow::bail!( + "found {} error{}", + style!(num_errors, &COUNT_STYLE), + if num_errors == 1 { "" } else { "s" }, + ), + }; + + let match_count = matches.values().map(|i| i.lines.len()).sum::(); + println!( + "Found {} match{} in {} file{}.", + style!(match_count, &COUNT_STYLE), + if match_count == 1 { "" } else { "es" }, + style!(matches.len(), &COUNT_STYLE), + if matches.len() == 1 { "" } else { "s" }, + ); + + // common options we'll use during the find & replace process across all files + let config = ReplaceOptions { + matcher: &matcher, + replace_with: args.replace.as_bytes(), + padding: match args.context { + Context::Num(x) => x, + Context::Infinite => u64::MAX, + }, + }; + + // loop over each file that has matches + for (path, match_info) in matches.iter_mut() { + // separate files by a newline + println!(); + + // If '--show' is set, the program should effectively do a dry run where it shows the + // changes without making any modifications. While we could write a simpler function, we + // instead use the same `replace_file` function to ensure that the behaviour is the same as + // what would normally happen. + + if args.show { + // we want to only show the patches, but not actually change anything + let src = std::fs::File::open(path).unwrap(); + + // perform the find & replace, but with no output file + let (cont, write_file) = replace_matches( + &config, + path, + &src, + None, + &mut match_info.lines, + Some(MenuOption::No), + ); + + // we provided `MenuOption::No`, so we shouldn't expect it to want to write + assert_eq!(cont, Continue::Yes); + assert_eq!(write_file, WriteFile::No); + } else { + // replace the file with a new file that we'll write to + let cont = + crate::util::replace_file(path, Some(match_info.modified), |original, new| { + // perform the find & replace + let (cont, write_file) = replace_matches( + &config, + path, + original, + Some(new), + &mut match_info.lines, + args.apply.then_some(MenuOption::Yes), + ); + + // inform `replace_file` whether it should replace the file or not + (write_file == WriteFile::Yes, cont) + }); + + // handle errors + let cont = match cont { + Ok(x) => x, + Err(ReplaceFileError::Io(e)) => { + return Err(e) + .with_context(|| format!("could not replace file '{}'", path.display())) + } + Err(ReplaceFileError::ModifiedTimeChanged) => { + return Err(anyhow::anyhow!( + "the file '{}' was modified by another program\n\ + Discarding all patches to this file and exiting.", + path.display(), + )) + } + }; + + if cont == Continue::No { + break; + } + } + } + + Ok(()) +} + +/// Find matches. Any errors will be printed to stdout. If there is an error: +/// - If `continue_on_err` is true, the error will be printed. +/// - If `continue_on_err` is false, the error will be printed and it will continue to walk the +/// filesystem looking for more errors, but it will stop searching files. +fn find_matches( + matcher: &RegexMatcher, + paths: &[impl AsRef], + continue_on_err: bool, +) -> Result, u64> { + let mut matches = BTreeMap::new(); + let mut num_errors = 0; + + if paths.is_empty() { + return Ok(matches); + } + + let mut searcher = Searcher::new(); + + let mut walk = WalkBuilder::new(paths.first().unwrap()); + for path in &paths[1..] { + walk.add(path); + } + let walk = walk.build(); + + for result in walk { + match result { + Ok(entry) => { + let path = entry.path(); + let meta = match std::fs::metadata(path) { + Ok(x) => x, + Err(e) => { + error!("{}: {e}", path.display()); + num_errors += 1; + continue; + } + }; + let modified_time = meta.modified().unwrap(); + + // this is only a very basic check; we may have already visited this file through + // some other path (relative or absolute path, another hard link to the same file, + // etc) and we don't defend against these here + if matches.contains_key(path) { + // already visited this path and it had a match + continue; + } + + if meta.is_dir() { + continue; + } + + if num_errors == 0 || continue_on_err { + let sink = Bytes(|line_num, _line| { + // TODO: even though we found a match, we might want to replace it with the + // same value (ex: "foo" -> "foo"), so we should also do a replace here and + // see if we really should record this + let MatchInfo { lines, .. } = matches + .entry(path.to_path_buf()) + .or_insert(MatchInfo::new(modified_time)); + + // line numbers are given starting from 1 + lines.push(line_num.checked_sub(1).unwrap()); + + Ok(true) + }); + + if let Err(e) = searcher.search_path(matcher, path, sink) { + // could not read the file + error!("{}: {e}", path.display()); + num_errors += 1; + } + } else { + // if we've already had an error, we still check if we can open the remaining + // files + if let Err(e) = File::open(path) { + // could not read the file + error!("{}: {e}", path.display()); + num_errors += 1; + } + } + } + Err(e) => { + error!("{e}"); + num_errors += 1; + } + } + } + + if num_errors == 0 || continue_on_err { + Ok(matches) + } else { + Err(num_errors) + } +} + +struct MatchInfo { + modified: SystemTime, + lines: Vec, +} + +impl MatchInfo { + pub fn new(modified: SystemTime) -> Self { + Self { + modified, + lines: Vec::new(), + } + } +} + +fn replace_matches( + options: &ReplaceOptions, + path: &Path, + src: &File, + empty_dest: Option<&File>, + line_nums: &mut [u64], + input: Option, +) -> (Continue, WriteFile) { + let mut src = BufReader::new(src); + let mut dest = empty_dest.map(BufWriter::new); + + // group adjacent lines into ranges + line_nums.sort(); + let hunk_ranges = crate::util::ranges(line_nums, options.padding); + let hunk_count: u64 = hunk_ranges.len().try_into().unwrap(); + + // current line of `src` + let mut current_line = 0; + + // did we make any of our own changes to `dest`? + let mut made_change = false; + + // do we want the program to continue after we return? + let mut cont = Continue::Yes; + + // a reusable buffer + let mut buf = Vec::new(); + + for (hunk_idx, hunk_range) in hunk_ranges.into_iter().enumerate() { + let hunk_idx: u64 = hunk_idx.try_into().unwrap(); + let path = (hunk_idx == 0).then_some(path); + + // copy file lines to dest file until we get to the first line of the hunk + while !hunk_range.contains(¤t_line) { + buf.clear(); + src.read_until(b'\n', &mut buf).unwrap(); + if buf.is_empty() { + // EOF + break; + } + if let Some(ref mut dest) = dest { + dest.write_all(&buf).unwrap(); + } + current_line += 1; + } + + let mut current_hunk = Vec::new(); + let hunk_start_line = current_line; + + // copy file lines to buffer until we read all lines of the hunk + while hunk_range.contains(¤t_line) { + let initial_len = current_hunk.len(); + src.read_until(b'\n', &mut current_hunk).unwrap(); + if current_hunk.len() == initial_len { + // EOF + break; + } + current_line += 1; + } + + // find & replace within this hunk + let mut replaced_hunk = Vec::new(); + crate::util::replace_regex( + options.matcher, + options.replace_with, + ¤t_hunk, + &mut replaced_hunk, + ) + .unwrap(); + + // check if anything changed + if current_hunk == replaced_hunk { + // nothing changed, so write the original hunk without applying any patch + if let Some(ref mut dest) = dest { + dest.write_all(¤t_hunk).unwrap(); + } + continue; + } + + // ask the user what to do + match crate::ui::patch_prompt( + ¤t_hunk, + &replaced_hunk, + path, + (hunk_idx, hunk_count), + hunk_start_line, + input, + ) { + PatchOption::WriteNew(x) => { + // this theoretically shouldn't be needed and it might panic on false positives, but + // it's unlikely that a patch would remove all lines of the hunk + if x.trim().is_empty() { + // TODO: remove this when we're more confident in the patches + let msg = "This patch removes all lines of the hunk. Are you sure that you want to continue [y/n]?"; + if !crate::ui::yes_no_prompt(msg) { + // write the hunk without applying the patch + if let Some(ref mut dest) = dest { + dest.write_all(¤t_hunk).unwrap(); + } + + cont = Continue::No; + break; + } + } + // write the new hunk + if let Some(ref mut dest) = dest { + dest.write_all(&x).unwrap(); + made_change = true; + } + } + PatchOption::WriteOriginal => { + // write the hunk without applying the patch + if let Some(ref mut dest) = dest { + dest.write_all(¤t_hunk).unwrap(); + } + } + PatchOption::Quit => { + // write the hunk without applying the patch + if let Some(ref mut dest) = dest { + dest.write_all(¤t_hunk).unwrap(); + } + + cont = Continue::No; + break; + } + } + } + + if !made_change { + return (cont, WriteFile::No); + } + + // if we made changes, there must have been a destination file + let Some(mut dest) = dest else { + panic!("Changes were apparently written, but we have no dest file"); + }; + + // TODO: we could possibly make this copy faster on specific Linux filesystems using + // `FICLONERANGE` + + // write out any internally buffered data in `src` + std::io::copy(&mut src.buffer(), &mut dest).unwrap(); + + // convert back to `File` to hopefully take advantage of `copy_file_range` during + // `std::io::copy` + let mut src: &File = src.into_inner(); + let mut dest: &File = dest.into_inner().unwrap(); + + // write remainder of file + std::io::copy(&mut src, &mut dest).unwrap(); + + (cont, WriteFile::Yes) +} + +pub struct ReplaceOptions<'a> { + matcher: &'a RegexMatcher, + replace_with: &'a [u8], + padding: u64, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum WriteFile { + Yes, + No, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum Continue { + Yes, + No, +} diff --git a/src/parse.rs b/src/parse.rs new file mode 100644 index 0000000..3618c7f --- /dev/null +++ b/src/parse.rs @@ -0,0 +1,38 @@ +use bstr::ByteSlice; + +pub fn lines_with_pos(bytes: &[u8]) -> impl Iterator { + bytes.lines().scan(0, |line_start, line| { + let x = *line_start; + *line_start += line.len() + 1; + Some((line, x)) + }) +} + +pub fn bytes_as_u64(bytes: &[u8]) -> Option { + std::str::from_utf8(bytes).ok()?.parse().ok() +} + +pub fn patch_block_header(bytes: &[u8]) -> Option<((u64, u64), (u64, u64))> { + let header = bytes.strip_prefix(b"@@ ")?.strip_suffix(b" @@")?; + + let (range_1, range_2) = header.split_at(header.find_byte(b' ')?); + let range_1 = range_1.strip_prefix(b"-")?; + let range_2 = range_2.strip_prefix(b" +")?; + + let mut range_1 = range_1.split_at(range_1.find_byte(b',')?); + let mut range_2 = range_2.split_at(range_2.find_byte(b',')?); + + range_1.1 = range_1.1.strip_prefix(b",")?; + range_2.1 = range_2.1.strip_prefix(b",")?; + + let range_1 = ( + crate::parse::bytes_as_u64(range_1.0)?, + crate::parse::bytes_as_u64(range_1.1)?, + ); + let range_2 = ( + crate::parse::bytes_as_u64(range_2.0)?, + crate::parse::bytes_as_u64(range_2.1)?, + ); + + Some((range_1, range_2)) +} diff --git a/src/ui.rs b/src/ui.rs new file mode 100644 index 0000000..48eb463 --- /dev/null +++ b/src/ui.rs @@ -0,0 +1,389 @@ +use std::ffi::{CStr, OsStr}; +use std::fs::File; +use std::io::{BufRead, Read, Seek, Write}; +use std::os::fd::{AsRawFd, FromRawFd}; +use std::os::unix::process::CommandExt; +use std::path::Path; +use std::process::Command; + +use bstr::ByteSlice; + +use crate::util::label; + +const FILENAME_STYLE: anstyle::Style = anstyle::Style::new().bold(); +const STAGE_STYLE: anstyle::Style = anstyle::AnsiColor::Blue.on_default().bold(); +const HELP_STYLE: anstyle::Style = anstyle::AnsiColor::Red.on_default().bold(); +pub const ERROR_STYLE: anstyle::Style = anstyle::Style::new().bold(); +pub const COUNT_STYLE: anstyle::Style = anstyle::Style::new().bold(); + +/// Start the editor with a file containing the given text. Once the user closes the editor, the +/// updated text will be returned. `None` will be returned if the editor exited with a non-zero +/// error code (for example `:cq` in vim). +fn user_edit( + text: &[u8], + editor_cmd: impl IntoIterator>, +) -> std::io::Result>> { + let mut editor_cmd = editor_cmd.into_iter(); + + // TODO: replace with C string literals in rust 1.77 + fn as_cstr(null_terminated_bytes: &[u8]) -> &CStr { + CStr::from_bytes_with_nul(null_terminated_bytes).unwrap() + } + + // create a memfd file + let edit_file = unsafe { libc::memfd_create(as_cstr(b"edit\0").as_ptr(), libc::MFD_CLOEXEC) }; + assert!(edit_file >= 0); + let mut edit_file = unsafe { File::from_raw_fd(edit_file) }; + + let edit_fd = edit_file.as_raw_fd(); + + // write the text to the file + edit_file.write_all(text)?; + + let mut cmd = Command::new(editor_cmd.next().expect("editor_cmd was empty")); + cmd.args(editor_cmd); + cmd.arg(format!("/proc/self/fd/{edit_fd}")); + + // remove the CLOEXEC flag after the fork + unsafe { + cmd.pre_exec(move || { + let flags = libc::fcntl(edit_fd, libc::F_GETFD, 0); + assert!(flags >= 0); + let flags = flags & !libc::FD_CLOEXEC; + let rv = libc::fcntl(edit_fd, libc::F_SETFD, flags); + assert_eq!(rv, 0); + Ok(()) + }); + } + + if !cmd.status()?.success() { + return Ok(None); + } + + // seek to the beginning of the file + edit_file.rewind()?; + + // read the modified file + let mut buf = Vec::new(); + edit_file.read_to_end(&mut buf)?; + + Ok(Some(buf)) +} + +fn menu_prompt( + patch: &diffy::Patch<[u8]>, + path: Option<&Path>, + progress: (u64, u64), + line_num: u64, + input: Option, +) -> MenuOption { + // format the patch + let mut patch_bytes = Vec::new(); + diffy::PatchFormatter::new() + .with_color() + .write_patch_into(patch, &mut patch_bytes) + .unwrap(); + + let patch_bytes = + crate::util::rewrite_patch_line_start(&patch_bytes, line_num as i128, true).unwrap(); + + let patch = String::from_utf8_lossy(&patch_bytes); + let mut patch = patch.trim(); + + if let Some(path) = path { + // show the file path + style_println!( + &FILENAME_STYLE, + "diff --{} {}", + env!("CARGO_PKG_NAME"), + path.display() + ); + } else { + // remove the first two lines ('---' and '+++') + let start = patch.match_indices('\n').nth(1).unwrap().0 + 1; + patch = &patch[start..]; + } + println!("{patch}"); + + if let Some(input) = input { + return input; + } + + let options = MenuOption::list() + .iter() + .map(|x| x.as_char()) + .chain(std::iter::once("?")) + .collect::>() + .join(","); + + let help = MenuOption::list() + .iter() + .map(|x| [x.as_char(), x.help()].join(" - ")) + .chain(std::iter::once("? - print help".to_string())) + .collect::>() + .join("\n"); + + loop { + style_print!( + &STAGE_STYLE, + "({}/{}) Apply this patch [{options}]? ", + progress.0 + 1, + progress.1, + ); + std::io::stdout().flush().unwrap(); + + // get the command from the user + let mut input = String::new(); + std::io::stdin().lock().read_line(&mut input).unwrap(); + + match input.trim().parse() { + Ok(x) => return x, + Err(_) => { + // could not parse the input, so print help text and patch then restart + style_println!(&HELP_STYLE, "{help}"); + println!("{patch}"); + } + } + } +} + +pub fn yes_no_prompt(prompt: &str) -> bool { + loop { + style_print!(&STAGE_STYLE, "{prompt} "); + std::io::stdout().flush().unwrap(); + + let mut input = String::new(); + std::io::stdin().lock().read_line(&mut input).unwrap(); + + match input.trim().chars().next() { + Some('y') => return true, + Some('n') => return false, + _ => {} + } + } +} + +pub fn patch_prompt( + original: &[u8], + replaced: &[u8], + mut src_path: Option<&Path>, + progress: (u64, u64), + line_num: u64, + input: Option, +) -> PatchOption { + // use a large context length so that diffy does not do its own hunking + let mut diff_options = diffy::DiffOptions::new(); + diff_options.set_context_len(usize::MAX); + + // the real patch + let patch = diff_options.create_patch_bytes(original, replaced); + + const ESC_STYLE: anstyle::Style = anstyle::Style::new().invert(); + let esc_styled = style!("ESC", &ESC_STYLE).to_string(); + + // a modified patch that is safe to print to the terminal + let safe_current = original.replace("\u{001b}", &esc_styled); + let safe_replaced = replaced.replace("\u{001b}", &esc_styled); + let safe_patch = diff_options.create_patch_bytes(&safe_current, &safe_replaced); + + label!('patch_prompt: { + // take the file path so that it's only ever shown once + let src_path = src_path.take(); + + // show the patch to the user and have them choose how to proceed + match menu_prompt(&safe_patch, src_path, progress, line_num, input) { + MenuOption::Yes => { + // apply the patch + let new_hunk = diffy::apply_bytes(original, &patch).unwrap(); + PatchOption::WriteNew(new_hunk) + } + MenuOption::No => PatchOption::WriteOriginal, + MenuOption::Quit => PatchOption::Quit, + MenuOption::Edit => label!('edit_prompt: { + const INVALID_PATCH_PROMPT: &str = + "Your patch is invalid. Edit again (saying \"no\" discards!) [y/n]?"; + const DOES_NOT_APPLY_PROMPT: &str = + "Your edited hunk does not apply. Edit again (saying \"no\" discards!) [y/n]?"; + + let edited = 'edit_hunk: { + let editor_cmd = crate::util::editor_cmd(); + + // allow the user to edit the patch + let Some(patch) = user_edit(&patch.to_bytes(), editor_cmd).unwrap() else { + // the editor didn't exit successfully + error!("The editor did not exit successfully."); + continue 'patch_prompt; + }; + + // if not valid utf-8, then it must not be empty + let is_empty = std::str::from_utf8(&patch) + .map(|x| x.trim().is_empty()) + .unwrap_or(false); + + // this also ignores whitespace since editors may add a newline at the end of + // the file + if is_empty { + // not even the patch header exists anymore + error!("The edited patch file was empty."); + continue 'patch_prompt; + } + + let patch = crate::util::rewrite_patch_line_counts(&patch); + + // create and apply the patch + let patch = match diffy::Patch::from_bytes(&patch) { + Ok(x) => x, + Err(e) => { + error!("{e}"); + break 'edit_hunk Err(INVALID_PATCH_PROMPT); + } + }; + let new_hunk = match diffy::apply_bytes(original, &patch) { + Ok(x) => x, + Err(e) => { + println!("{e}"); + break 'edit_hunk Err(DOES_NOT_APPLY_PROMPT); + } + }; + + Ok(new_hunk) + }; + + match edited { + Ok(edited) => PatchOption::WriteNew(edited), + Err(msg) => { + if yes_no_prompt(msg) { + // answered "yes", so edit again + continue 'edit_prompt; + } + // answered "no", so discard and use original + PatchOption::WriteOriginal + } + } + }), + } + }) +} + +pub enum PatchOption { + WriteNew(Vec), + WriteOriginal, + Quit, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum MenuOption { + Yes, + No, + Quit, + Edit, +} + +impl MenuOption { + pub const fn list() -> &'static [Self] { + &[Self::Yes, Self::No, Self::Quit, Self::Edit] + } + + pub const fn as_char(&self) -> &'static str { + // return a str instead of a char since they're much easier to work with (there is no char + // -> str const function) + match self { + Self::Yes => "y", + Self::No => "n", + Self::Quit => "q", + Self::Edit => "e", + } + } + + pub const fn help(&self) -> &'static str { + match self { + Self::Yes => "replace this hunk", + Self::No => "do not replace this hunk", + Self::Quit => "quit; do not replace this hunk or any future hunks", + Self::Edit => "manually edit the current hunk", + } + } +} + +impl std::str::FromStr for MenuOption { + type Err = (); + + fn from_str(s: &str) -> Result { + const YES_STR: &str = MenuOption::Yes.as_char(); + const NO_STR: &str = MenuOption::No.as_char(); + const QUIT_STR: &str = MenuOption::Quit.as_char(); + const EDIT_STR: &str = MenuOption::Edit.as_char(); + + Ok(match s { + YES_STR => Self::Yes, + NO_STR => Self::No, + QUIT_STR => Self::Quit, + EDIT_STR => Self::Edit, + _ => return Err(()), + }) + } +} + +macro_rules! style { + ($str:expr, $style:expr) => {{ + // for type checking + let _style: &anstyle::Style = $style; + format_args!("{}{}{}", $style, $str, anstyle::Reset) + }}; +} +pub(crate) use style; + +macro_rules! style_print { + () => {{ + print!() + }}; + ($style:expr) => {{ + // for type checking + let _style: &anstyle::Style = $style; + print!() + }}; + ($style:expr, $fmt:literal $($arg:tt)*) => {{ + let style: &anstyle::Style = $style; + print!("{style}{}{style:#}", format_args!($fmt $($arg)*)) + }}; +} +pub(crate) use style_print; + +macro_rules! style_println { + () => {{ + println!() + }}; + ($style:expr) => {{ + // for type checking + let _style: &anstyle::Style = $style; + println!() + }}; + ($style:expr, $fmt:literal $($arg:tt)*) => {{ + let style: &anstyle::Style = $style; + println!("{style}{}{style:#}", format_args!($fmt $($arg)*)) + }}; +} +pub(crate) use style_println; + +macro_rules! error { + () => {{ + error!("") + }}; + ($fmt:literal $($arg:tt)*) => {{ + println!("{} {}", style!("ERROR:", &crate::ui::ERROR_STYLE), format_args!($fmt $($arg)*)) + }}; +} +pub(crate) use error; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_patch_options() { + for (option, as_str) in MenuOption::list().iter().map(|x| (*x, x.as_char())) { + // test round-trip + assert_eq!(as_str.parse(), Ok(option)); + } + } +} diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..64e8a51 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,513 @@ +use std::ffi::{CString, OsStr, OsString}; +use std::fs::{File, OpenOptions}; +use std::io::Write; +use std::os::fd::AsRawFd; +use std::os::unix::ffi::{OsStrExt, OsStringExt}; +use std::os::unix::fs::{OpenOptionsExt, PermissionsExt}; +use std::path::Path; +use std::process::Command; +use std::sync::OnceLock; +use std::time::SystemTime; + +use bstr::ByteSlice; +use grep_matcher::{Captures, Matcher}; +use grep_regex::RegexMatcher; + +pub fn ranges(sorted_list: &[u64], padding: u64) -> Vec> { + let mut ranges = Vec::new(); + let padding = std::num::Saturating(padding); + + for x in sorted_list { + let x = std::num::Saturating(*x); + + let Some(range) = ranges.last_mut() else { + let start = x - padding; + let end = x + padding; + ranges.push(start.0..=end.0); + continue; + }; + + if range.contains(&(x - padding).0) { + if *range.end() < (x + padding).0 { + let end = x + padding; + *range = *range.start()..=end.0; + } + continue; + } + + let start = x - padding; + let end = x + padding; + ranges.push(start.0..=end.0); + } + + ranges +} + +pub fn replace_file( + path: impl AsRef, + modified_at: Option, + f: impl FnOnce(&File, &File) -> (bool, T), +) -> Result { + let path = path.as_ref(); + + if !path.is_file() { + return Err(std::io::Error::new(std::io::ErrorKind::InvalidInput, "not a file").into()); + } + + // TODO: this path may already exist, so choose a better path? (linkat below won't overwrite + // existing files, so this won't cause us to lose data) + let tmp_path = { + let mut ext = path.extension().unwrap_or(OsStr::new("")).to_os_string(); + ext.push(OsStr::new(".asdf123.tmp")); + path.with_extension(ext) + }; + + let tmp_c_path = CString::new(tmp_path.as_os_str().as_bytes()).unwrap(); + + let original = File::open(path)?; + + // for paths like "foo", rust will return a parent of "" which is not useful for syscalls so we + // replace it with "./" + let mut parent_path = path.parent().unwrap(); + if parent_path == Path::new("") { + parent_path = Path::new("./"); + } + + // create an unnamed file on the mount for the path + let new = OpenOptions::new() + .write(true) + .truncate(true) + .custom_flags(libc::O_TMPFILE) + .open(parent_path)?; + + // copy only the user/group/other read/write/execute permission bits + let mask = libc::S_IRWXU | libc::S_IRWXG | libc::S_IRWXO; + + // set the permissions after creating the file so that it's not affected by the umask + new.set_permissions(read_permissions(&original, mask)?)?; + + // the path to the new file in the /proc mount + let mut procfd_c_path = Vec::new(); + procfd_c_path.extend(b"/proc/self/fd/"); + procfd_c_path.extend(new.as_raw_fd().to_string().as_bytes()); + let procfd_c_path = CString::new(procfd_c_path).unwrap(); + + // TODO: use fallocate() to ensure we have approx enough space (the new file might be larger or + // smaller than the original, but will typically be similar)? + + let (do_replace_file, rv) = f(&original, &new); + + // the user-provided closure asked us to stop + if !do_replace_file { + return Ok(rv); + }; + + if let Some(modified_at) = modified_at { + // the current "modified" time for the file + let latest_modified = std::fs::metadata(path)?.modified()?; + + // return an error if the file's "modified" timestamps differ + if latest_modified != modified_at { + return Err(ReplaceFileError::ModifiedTimeChanged); + } + } + + // give the new file a temporary name + let linkat_rv = unsafe { + libc::linkat( + libc::AT_FDCWD, + procfd_c_path.as_ptr(), + libc::AT_FDCWD, + tmp_c_path.as_ptr(), + libc::AT_SYMLINK_FOLLOW, + ) + }; + if linkat_rv != 0 { + // may have failed if a file at `tmp_path` already exists + return Err(std::io::Error::last_os_error().into()); + } + + // replace the original file at `path` with the new file + std::fs::rename(&tmp_path, path)?; + + Ok(rv) +} + +#[derive(Debug)] +pub enum ReplaceFileError { + Io(std::io::Error), + ModifiedTimeChanged, +} + +impl From for ReplaceFileError { + fn from(e: std::io::Error) -> Self { + Self::Io(e) + } +} + +impl std::fmt::Display for ReplaceFileError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Io(e) => write!(f, "{e}"), + Self::ModifiedTimeChanged => { + write!(f, "the file's \"modified\" timestamp unexpectedly changed") + } + } + } +} + +impl std::error::Error for ReplaceFileError {} + +/// Returns the file permissions without any file type bits. Also applies an additional bitmask to +/// the returned mode. +fn read_permissions(file: &File, mask: u32) -> std::io::Result { + // `std::fs::Metadata::permissions()` contains everything in the `st_mode` stat field, which + // also contains the file type which we mask out + let mode = file.metadata()?.permissions().mode() & !libc::S_IFMT; + let mode = mode & mask; + Ok(std::fs::Permissions::from_mode(mode)) +} + +pub fn editor_cmd() -> impl Iterator> { + static EDITOR_CMD: OnceLock> = OnceLock::new(); + + // this is roughly what `sudo -e` does when parsing env variables + fn split_whitespace(bytes: &[u8]) -> Vec { + bytes + .fields() + .map(|x| OsString::from_vec(x.to_vec())) + .collect() + } + + // returns `None` if `name` isn't set or if empty + fn env_var(name: &str) -> Option> { + if let Some(cmd) = std::env::var_os(name) { + let cmd = split_whitespace(cmd.as_bytes()); + if !cmd.is_empty() { + return Some(cmd); + } + } + None + } + + let cmd = EDITOR_CMD.get_or_init(|| { + if let Some(cmd) = env_var("VISUAL") { + return cmd; + } + + if let Some(cmd) = env_var("EDITOR") { + return cmd; + } + + if let Some(cmd) = env_var("GIT_EDITOR") { + return cmd; + } + + if let Ok(output) = Command::new("git") + .arg("config") + .arg("--null") + .arg("core.editor") + .output() + { + let mut output = output.stdout; + // the last byte should be a nul + assert_eq!(Some(0), output.pop()); + + if !output.is_empty() { + let cmd = split_whitespace(&output); + if !cmd.is_empty() { + return cmd; + } + } + } + + // if we can't find an editor, choose the best editor + [OsString::from_vec(b"vim".to_vec())].to_vec() + }); + + assert!(!cmd.is_empty()); + + cmd.iter() +} + +pub fn replace_regex( + matcher: &RegexMatcher, + replacement: &[u8], + haystack: &[u8], + dest: &mut Vec, +) -> Result<(), ::Error> { + let mut captures = matcher.new_captures().unwrap(); + matcher.replace_with_captures(haystack, &mut captures, dest, |caps, dest| { + caps.interpolate( + |name| matcher.capture_index(name), + haystack, + replacement, + dest, + ); + true + }) +} + +pub fn rewrite_patch_line_counts(bytes: &[u8]) -> std::borrow::Cow<[u8]> { + let result = (|| { + let mut lines = crate::parse::lines_with_pos(bytes); + + let (header, header_start) = lines.nth(2)?; + + let (range_1, range_2) = crate::parse::patch_block_header(header)?; + + let mut content_start = None; + let mut line_counts = (0, 0); + + // count the number of + and - lines + for (line, pos) in lines { + if content_start.is_none() { + content_start = Some(pos); + } + + match line.first() { + Some(b' ') | None => { + line_counts.0 += 1; + line_counts.1 += 1; + } + Some(b'-') => line_counts.0 += 1, + Some(b'+') => line_counts.1 += 1, + _ => return None, + } + } + + if (range_1.1, range_2.1) == line_counts { + // no need to change the patch + return None; + } + + let content_start = content_start?; + + // build the new patch + let mut new_patch = Vec::new(); + + // add the header + new_patch.extend_from_slice(&bytes[..header_start]); + + // write the new line numbers + writeln!( + &mut new_patch, + "@@ -{},{} +{},{} @@", + range_1.0, line_counts.0, range_2.0, line_counts.1, + ) + .ok()?; + + // add the patch contents + new_patch.extend_from_slice(&bytes[content_start..]); + + Some(new_patch) + })(); + + match result { + Some(x) => std::borrow::Cow::Owned(x), + None => std::borrow::Cow::Borrowed(bytes), + } +} + +pub fn rewrite_patch_line_start(bytes: &[u8], offset: i128, ansi: bool) -> Option> { + let mut lines = crate::parse::lines_with_pos(bytes); + let (mut header, header_start) = lines.nth(2)?; + let (_, content_start) = lines.next()?; + + const ANSI_RESET: &[u8] = b"\x1b[0m"; + const ANSI_HEADER_COLOR: &[u8] = b"\x1b[36m"; + + if ansi { + header = header.strip_prefix(ANSI_RESET)?; + header = header.strip_prefix(ANSI_HEADER_COLOR)?; + header = header.strip_suffix(ANSI_RESET)?; + } + + let (mut pair_1, mut pair_2) = crate::parse::patch_block_header(header)?; + + let (offset, positive_offset) = if offset >= 0 { + (u64::try_from(offset).ok()?, true) + } else { + (u64::try_from(-offset).ok()?, false) + }; + + if positive_offset { + pair_1.0 = pair_1.0.checked_add(offset)?; + pair_2.0 = pair_2.0.checked_add(offset)?; + } else { + pair_1.0 = pair_1.0.checked_sub(offset)?; + pair_2.0 = pair_2.0.checked_sub(offset)?; + } + + // build the new patch + let mut new_patch = Vec::new(); + + // add the header + new_patch.extend_from_slice(&bytes[..header_start]); + + if ansi { + new_patch.extend_from_slice(ANSI_RESET); + new_patch.extend_from_slice(ANSI_HEADER_COLOR); + } + + // write the new line numbers + write!( + &mut new_patch, + "@@ -{},{} +{},{} @@", + pair_1.0, pair_1.1, pair_2.0, pair_2.1, + ) + .ok()?; + + if ansi { + new_patch.extend_from_slice(ANSI_RESET); + } + + writeln!(&mut new_patch).unwrap(); + + // add the patch contents + new_patch.extend_from_slice(&bytes[content_start..]); + + Some(new_patch) +} + +/// A label you can jump to using `continue`. +/// +/// ``` +/// let x: u32 = label!('start { +/// let input = todo!(); +/// match input { +/// "retry" => continue 'start, +/// "one" => 1, +/// "two" => 2, +/// _ => input.parse().unwrap(), +/// } +/// }); +/// ``` +macro_rules! label { + ($label:lifetime: $code:block) => { + $label: loop { + let _rv = { + $code + }; + #[allow(unreachable_code)] + { + break $label _rv; + } + } + }; +} +pub(crate) use label; + +#[cfg(test)] +mod tests { + use super::*; + + use std::io::{Read, Write}; + + #[test] + fn test_ranges() { + let list = [1, 2, 10, 12, 35, 38, 55, u64::MAX]; + let padding = 5; + assert_eq!( + ranges(&list, padding), + [0..=17, 30..=43, 50..=60, u64::MAX - 5..=u64::MAX], + ); + + let list = [1, 2, 10, 12, 35, 38, 55, u64::MAX]; + let padding = u64::MAX; + assert_eq!(ranges(&list, padding), [0..=u64::MAX]); + + let list = []; + let padding = 5; + assert_eq!(ranges(&list, padding), []); + + let list = [1, 2, 5, 7, 100]; + let padding = 0; + assert_eq!( + ranges(&list, padding), + [1..=1, 2..=2, 5..=5, 7..=7, 100..=100] + ); + + let list = [1, 2, 5, 7, 100]; + let padding = 1; + assert_eq!(ranges(&list, padding), [0..=3, 4..=8, 99..=101]); + } + + #[test] + fn test_replace_file() { + let mut file = tempfile::Builder::new().tempfile().unwrap(); + file.write_all(b"hello world\n").unwrap(); + + replace_file(file.path(), None, |mut original, mut new| { + new.write_all(b"foo ").unwrap(); + let mut buf = Vec::new(); + original.read_to_end(&mut buf).unwrap(); + new.write_all(&buf).unwrap(); + (true, ()) + }) + .unwrap(); + + // `file` doesn't point to the new file located at `file.path()`, so it's confusing to leave + // the file open + let file = file.into_temp_path(); + + // verify the nre file has the correct contents + assert_eq!(std::fs::read(&file).unwrap(), b"foo hello world\n"); + + ///////// + + let mut file = tempfile::Builder::new().tempfile().unwrap(); + file.write_all(b"hello world\n").unwrap(); + + replace_file(file.path(), None, |mut original, mut new| { + new.write_all(b"foo ").unwrap(); + let mut buf = Vec::new(); + original.read_to_end(&mut buf).unwrap(); + new.write_all(&buf).unwrap(); + (false, ()) + }) + .unwrap(); + + // verify the file has the same contents + assert_eq!(std::fs::read(file.path()).unwrap(), b"hello world\n"); + + ///////// + + let mut file = tempfile::Builder::new().tempfile().unwrap(); + file.write_all(b"hello world\n").unwrap(); + + // user readable and executable + let target_permissions = std::fs::Permissions::from_mode(libc::S_IXUSR | libc::S_IRUSR); + + // set the permissions for the file + file.as_file() + .set_permissions(target_permissions.clone()) + .unwrap(); + assert_eq!( + read_permissions(&file.as_file(), u32::MAX).unwrap(), + target_permissions, + ); + + replace_file(file.path(), None, |mut original, mut new| { + new.write_all(b"foo ").unwrap(); + let mut buf = Vec::new(); + original.read_to_end(&mut buf).unwrap(); + new.write_all(&buf).unwrap(); + (true, ()) + }) + .unwrap(); + + // `file` doesn't point to the new file located at `file.path()`, so it's confusing to leave + // the file open + let file = file.into_temp_path(); + + // verify the nre file has the correct contents + assert_eq!(std::fs::read(&file).unwrap(), b"foo hello world\n"); + + // verify the new file has the same permissions + assert_eq!( + read_permissions(&File::open(&file).unwrap(), u32::MAX).unwrap(), + target_permissions, + ); + } +}