mirror of
https://github.com/encounter/objdiff.git
synced 2025-08-18 18:01:38 +00:00
Compare commits
11 Commits
v3.0.0-bet
...
main
Author | SHA1 | Date | |
---|---|---|---|
678210d58a | |||
4302821615 | |||
c4b4244b59 | |||
52c138bf06 | |||
813c8aa539 | |||
0f0aaab795 | |||
b21892be31 | |||
247d6da94b | |||
bd95faa9c3 | |||
2c57e4960f | |||
cff4be2979 |
97
Cargo.lock
generated
97
Cargo.lock
generated
@ -123,7 +123,7 @@ dependencies = [
|
|||||||
"clipboard-win",
|
"clipboard-win",
|
||||||
"image",
|
"image",
|
||||||
"log",
|
"log",
|
||||||
"objc2 0.6.1",
|
"objc2 0.6.2",
|
||||||
"objc2-app-kit 0.3.1",
|
"objc2-app-kit 0.3.1",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-core-graphics",
|
"objc2-core-graphics",
|
||||||
@ -390,9 +390,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-std"
|
name = "async-std"
|
||||||
version = "1.13.1"
|
version = "1.13.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "730294c1c08c2e0f85759590518f6333f0d5a0a766a27d519c1b244c3dfd8a24"
|
checksum = "2c8e079a4ab67ae52b7403632e4618815d6db36d2a010cfe41b02c1b1578f93b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-channel 1.9.0",
|
"async-channel 1.9.0",
|
||||||
"async-global-executor",
|
"async-global-executor",
|
||||||
@ -436,9 +436,9 @@ checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-trait"
|
name = "async-trait"
|
||||||
version = "0.1.88"
|
version = "0.1.89"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5"
|
checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -556,7 +556,7 @@ version = "0.6.1"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2"
|
checksum = "340d2f0bdb2a43c1d3cd40513185b2bd7def0aa1052f956455114bc98f82dcf2"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"objc2 0.6.1",
|
"objc2 0.6.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1126,7 +1126,7 @@ dependencies = [
|
|||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"block2 0.6.1",
|
"block2 0.6.1",
|
||||||
"libc",
|
"libc",
|
||||||
"objc2 0.6.1",
|
"objc2 0.6.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -1184,9 +1184,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ecolor"
|
name = "ecolor"
|
||||||
version = "0.32.0"
|
version = "0.32.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4a631732d995184114016fab22fc7e3faf73d6841c2d7650395fe251fbcd9285"
|
checksum = "b6a7fc3172c2ef56966b2ce4f84177e159804c40b9a84de8861558ce4a59f422"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"emath",
|
"emath",
|
||||||
@ -1195,9 +1195,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "eframe"
|
name = "eframe"
|
||||||
version = "0.32.0"
|
version = "0.32.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c790ccfbb3dd556588342463454b2b2b13909e5fdce5bc2a1432a8aa69c8b7a"
|
checksum = "34037a80dc03a4147e1684bff4e4fdab2b1408d715d7b78470cd3179258964b9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
@ -1236,9 +1236,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "egui"
|
name = "egui"
|
||||||
version = "0.32.0"
|
version = "0.32.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8470210c95a42cc985d9ffebfd5067eea55bdb1c3f7611484907db9639675e28"
|
checksum = "49e2be082f77715496b4a39fdc6f5dc7491fefe2833111781b8697ea6ee919a7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"ahash",
|
"ahash",
|
||||||
@ -1256,9 +1256,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "egui-wgpu"
|
name = "egui-wgpu"
|
||||||
version = "0.32.0"
|
version = "0.32.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "14de9942d8b9e99e2d830403c208ab1a6e052e925a7456a4f6f66d567d90de1d"
|
checksum = "64c7277a171ec1b711080ddb3b0bfa1b3aa9358834d5386d39e83fbc16d61212"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
@ -1276,9 +1276,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "egui-winit"
|
name = "egui-winit"
|
||||||
version = "0.32.0"
|
version = "0.32.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c490804a035cec9c826082894a3e1ecf4198accd3817deb10f7919108ebafab0"
|
checksum = "fe6d8b0f8d6de4d43e794e343f03bacc3908aada931f0ed6fd7041871388a590"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"arboard",
|
"arboard",
|
||||||
@ -1296,9 +1296,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "egui_extras"
|
name = "egui_extras"
|
||||||
version = "0.32.0"
|
version = "0.32.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0f791a5937f518249016b276b3639ad2aa3824048b6f2161ec2b431ab325880a"
|
checksum = "8ae8f23013328beb6be7ab29c75807142e8e1c7951643780a813e54cceaa9929"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"egui",
|
"egui",
|
||||||
@ -1310,9 +1310,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "egui_glow"
|
name = "egui_glow"
|
||||||
version = "0.32.0"
|
version = "0.32.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d44f3fd4fdc5f960c9e9ef7327c26647edc3141abf96102980647129d49358e6"
|
checksum = "0ab645760288e42eab70283a5cccf44509a6f43b554351855d3c73594bfe3c23"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
@ -1334,9 +1334,9 @@ checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "emath"
|
name = "emath"
|
||||||
version = "0.32.0"
|
version = "0.32.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "45f057b141e7e46340c321400be74b793543b1b213036f0f989c35d35957c32e"
|
checksum = "935df67dc48fdeef132f2f7ada156ddc79e021344dd42c17f066b956bb88dde3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"serde",
|
"serde",
|
||||||
@ -1440,9 +1440,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "epaint"
|
name = "epaint"
|
||||||
version = "0.32.0"
|
version = "0.32.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94cca02195f0552c17cabdc02f39aa9ab6fbd815dac60ab1cd3d5b0aa6f9551c"
|
checksum = "b66fc0a5a9d322917de9bd3ac7d426ca8aa3127fbf1e76fae5b6b25e051e06a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ab_glyph",
|
"ab_glyph",
|
||||||
"ahash",
|
"ahash",
|
||||||
@ -1459,9 +1459,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "epaint_default_fonts"
|
name = "epaint_default_fonts"
|
||||||
version = "0.32.0"
|
version = "0.32.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e8495e11ed527dff39663b8c36b6c2b2799d7e4287fb90556e455d72eca0b4d3"
|
checksum = "4f6cf8ce0fb817000aa24f5e630bda904a353536bd430b83ebc1dceee95b4a3a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "equivalent"
|
name = "equivalent"
|
||||||
@ -1876,8 +1876,7 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gimli"
|
name = "gimli"
|
||||||
version = "0.32.0"
|
version = "0.32.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/gimli-rs/gimli?rev=7335f00e7c39fd501511584fefb0ba974117c950#7335f00e7c39fd501511584fefb0ba974117c950"
|
||||||
checksum = "93563d740bc9ef04104f9ed6f86f1e3275c2cdafb95664e26584b9ca807a8ffe"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gl_generator"
|
name = "gl_generator"
|
||||||
@ -1942,7 +1941,7 @@ dependencies = [
|
|||||||
"glutin_glx_sys",
|
"glutin_glx_sys",
|
||||||
"glutin_wgl_sys",
|
"glutin_wgl_sys",
|
||||||
"libloading",
|
"libloading",
|
||||||
"objc2 0.6.1",
|
"objc2 0.6.2",
|
||||||
"objc2-app-kit 0.3.1",
|
"objc2-app-kit 0.3.1",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-foundation 0.3.1",
|
"objc2-foundation 0.3.1",
|
||||||
@ -3181,9 +3180,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objc2"
|
name = "objc2"
|
||||||
version = "0.6.1"
|
version = "0.6.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "88c6597e14493ab2e44ce58f2fdecf095a51f12ca57bec060a11c57332520551"
|
checksum = "561f357ba7f3a2a61563a186a163d0a3a5247e1089524a3981d49adb775078bc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"objc2-encode",
|
"objc2-encode",
|
||||||
]
|
]
|
||||||
@ -3212,7 +3211,7 @@ checksum = "e6f29f568bec459b0ddff777cec4fe3fd8666d82d5a40ebd0ff7e66134f89bcc"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"block2 0.6.1",
|
"block2 0.6.1",
|
||||||
"objc2 0.6.1",
|
"objc2 0.6.2",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-core-graphics",
|
"objc2-core-graphics",
|
||||||
"objc2-foundation 0.3.1",
|
"objc2-foundation 0.3.1",
|
||||||
@ -3262,7 +3261,7 @@ checksum = "1c10c2894a6fed806ade6027bcd50662746363a9589d3ec9d9bef30a4e4bc166"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"dispatch2",
|
"dispatch2",
|
||||||
"objc2 0.6.1",
|
"objc2 0.6.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3273,7 +3272,7 @@ checksum = "989c6c68c13021b5c2d6b71456ebb0f9dc78d752e86a98da7c716f4f9470f5a4"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"dispatch2",
|
"dispatch2",
|
||||||
"objc2 0.6.1",
|
"objc2 0.6.2",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-io-surface",
|
"objc2-io-surface",
|
||||||
]
|
]
|
||||||
@ -3328,7 +3327,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c"
|
checksum = "900831247d2fe1a09a683278e5384cfb8c80c79fe6b166f9d14bfdde0ea1b03c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"objc2 0.6.1",
|
"objc2 0.6.2",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3339,7 +3338,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c"
|
checksum = "7282e9ac92529fa3457ce90ebb15f4ecbc383e8338060960760fa2cf75420c3c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.9.1",
|
"bitflags 2.9.1",
|
||||||
"objc2 0.6.1",
|
"objc2 0.6.2",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -3437,7 +3436,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-cli"
|
name = "objdiff-cli"
|
||||||
version = "3.0.0-beta.14"
|
version = "3.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"argp",
|
"argp",
|
||||||
@ -3460,7 +3459,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-core"
|
name = "objdiff-core"
|
||||||
version = "3.0.0-beta.14"
|
version = "3.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"arm-attr",
|
"arm-attr",
|
||||||
@ -3483,7 +3482,7 @@ dependencies = [
|
|||||||
"notify-debouncer-full",
|
"notify-debouncer-full",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"objdiff-core",
|
"objdiff-core",
|
||||||
"object 0.37.1",
|
"object 0.37.3",
|
||||||
"pbjson",
|
"pbjson",
|
||||||
"pbjson-build",
|
"pbjson-build",
|
||||||
"powerpc",
|
"powerpc",
|
||||||
@ -3515,9 +3514,10 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-gui"
|
name = "objdiff-gui"
|
||||||
version = "3.0.0-beta.14"
|
version = "3.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"argp",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"const_format",
|
"const_format",
|
||||||
"cwdemangle",
|
"cwdemangle",
|
||||||
@ -3551,7 +3551,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "objdiff-wasm"
|
name = "objdiff-wasm"
|
||||||
version = "3.0.0-beta.14"
|
version = "3.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
"objdiff-core",
|
"objdiff-core",
|
||||||
@ -3573,8 +3573,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "object"
|
name = "object"
|
||||||
version = "0.37.1"
|
version = "0.37.3"
|
||||||
source = "git+https://github.com/gimli-rs/object?rev=16ff70aa6fbd97d6bb7b92375929f4d72414c32b#16ff70aa6fbd97d6bb7b92375929f4d72414c32b"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
@ -4452,7 +4453,7 @@ dependencies = [
|
|||||||
"dispatch2",
|
"dispatch2",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"log",
|
"log",
|
||||||
"objc2 0.6.1",
|
"objc2 0.6.2",
|
||||||
"objc2-app-kit 0.3.1",
|
"objc2-app-kit 0.3.1",
|
||||||
"objc2-core-foundation",
|
"objc2-core-foundation",
|
||||||
"objc2-foundation 0.3.1",
|
"objc2-foundation 0.3.1",
|
||||||
@ -5069,9 +5070,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.104"
|
version = "2.0.105"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
|
checksum = "7bc3fcb250e53458e712715cf74285c1f889686520d79294a9ef3bd7aa1fc619"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@ -6046,7 +6047,7 @@ dependencies = [
|
|||||||
"jni",
|
"jni",
|
||||||
"log",
|
"log",
|
||||||
"ndk-context",
|
"ndk-context",
|
||||||
"objc2 0.6.1",
|
"objc2 0.6.2",
|
||||||
"objc2-foundation 0.3.1",
|
"objc2-foundation 0.3.1",
|
||||||
"url",
|
"url",
|
||||||
"web-sys",
|
"web-sys",
|
||||||
|
@ -14,7 +14,7 @@ strip = "debuginfo"
|
|||||||
codegen-units = 1
|
codegen-units = 1
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "3.0.0-beta.14"
|
version = "3.0.0"
|
||||||
authors = ["Luke Street <luke@street.dev>"]
|
authors = ["Luke Street <luke@street.dev>"]
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
|
@ -106,6 +106,9 @@ file as well. You can then add `objdiff.json` to your `.gitignore` to prevent it
|
|||||||
"*.txt",
|
"*.txt",
|
||||||
"*.json"
|
"*.json"
|
||||||
],
|
],
|
||||||
|
"ignore_patterns": [
|
||||||
|
"build/**/*"
|
||||||
|
],
|
||||||
"units": [
|
"units": [
|
||||||
{
|
{
|
||||||
"name": "main/MetroTRK/mslsupp",
|
"name": "main/MetroTRK/mslsupp",
|
||||||
@ -141,6 +144,10 @@ It's unlikely you'll want to disable this, unless you're using an external tool
|
|||||||
If any of these files change, objdiff will automatically rebuild the objects and re-compare them.
|
If any of these files change, objdiff will automatically rebuild the objects and re-compare them.
|
||||||
If not specified, objdiff will use the default patterns listed above.
|
If not specified, objdiff will use the default patterns listed above.
|
||||||
|
|
||||||
|
`ignore_patterns` _(optional)_: A list of glob patterns to explicitly ignore when watching for changes.
|
||||||
|
([Supported syntax](https://docs.rs/globset/latest/globset/#syntax))
|
||||||
|
If not specified, objdiff will use the default patterns listed above.
|
||||||
|
|
||||||
`units` _(optional)_: If specified, objdiff will display a list of objects in the sidebar for easy navigation.
|
`units` _(optional)_: If specified, objdiff will display a list of objects in the sidebar for easy navigation.
|
||||||
|
|
||||||
> `name` _(optional)_: The name of the object in the UI. If not specified, the object's `path` will be used.
|
> `name` _(optional)_: The name of the object in the UI. If not specified, the object's `path` will be used.
|
||||||
|
@ -74,6 +74,16 @@
|
|||||||
"*.json"
|
"*.json"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"ignore_patterns": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "List of glob patterns to explicitly ignore when watching for changes.\nFiles matching these patterns will not trigger a rebuild.\nSupported syntax: https://docs.rs/globset/latest/globset/#syntax",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"default": [
|
||||||
|
"build/**/*"
|
||||||
|
]
|
||||||
|
},
|
||||||
"objects": {
|
"objects": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"description": "Use units instead.",
|
"description": "Use units instead.",
|
||||||
|
@ -19,7 +19,6 @@ use crossterm::{
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
use objdiff_core::{
|
use objdiff_core::{
|
||||||
bindings::diff::DiffResult,
|
|
||||||
build::{
|
build::{
|
||||||
BuildConfig, BuildStatus,
|
BuildConfig, BuildStatus,
|
||||||
watcher::{Watcher, create_watcher},
|
watcher::{Watcher, create_watcher},
|
||||||
@ -28,7 +27,7 @@ use objdiff_core::{
|
|||||||
ProjectConfig, ProjectObject, ProjectObjectMetadata, build_globset,
|
ProjectConfig, ProjectObject, ProjectObjectMetadata, build_globset,
|
||||||
path::{check_path_buf, platform_path, platform_path_serde_option},
|
path::{check_path_buf, platform_path, platform_path_serde_option},
|
||||||
},
|
},
|
||||||
diff::{self, DiffObjConfig, MappingConfig, ObjectDiff},
|
diff::{DiffObjConfig, MappingConfig, ObjectDiff},
|
||||||
jobs::{
|
jobs::{
|
||||||
Job, JobQueue, JobResult,
|
Job, JobQueue, JobResult,
|
||||||
objdiff::{ObjDiffConfig, start_build},
|
objdiff::{ObjDiffConfig, start_build},
|
||||||
@ -40,10 +39,7 @@ use typed_path::{Utf8PlatformPath, Utf8PlatformPathBuf};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
cmd::apply_config_args,
|
cmd::apply_config_args,
|
||||||
util::{
|
util::term::crossterm_panic_handler,
|
||||||
output::{OutputFormat, write_output},
|
|
||||||
term::crossterm_panic_handler,
|
|
||||||
},
|
|
||||||
views::{EventControlFlow, EventResult, UiView, function_diff::FunctionDiffUi},
|
views::{EventControlFlow, EventResult, UiView, function_diff::FunctionDiffUi},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -63,12 +59,6 @@ pub struct Args {
|
|||||||
#[argp(option, short = 'u')]
|
#[argp(option, short = 'u')]
|
||||||
/// Unit name within project
|
/// Unit name within project
|
||||||
unit: Option<String>,
|
unit: Option<String>,
|
||||||
#[argp(option, short = 'o', from_str_fn(platform_path))]
|
|
||||||
/// Output file (one-shot mode) ("-" for stdout)
|
|
||||||
output: Option<Utf8PlatformPathBuf>,
|
|
||||||
#[argp(option)]
|
|
||||||
/// Output format (json, json-pretty, proto) (default: json)
|
|
||||||
format: Option<String>,
|
|
||||||
#[argp(positional)]
|
#[argp(positional)]
|
||||||
/// Function symbol to diff
|
/// Function symbol to diff
|
||||||
symbol: Option<String>,
|
symbol: Option<String>,
|
||||||
@ -171,11 +161,7 @@ pub fn run(args: Args) -> Result<()> {
|
|||||||
_ => bail!("Either target and base or project and unit must be specified"),
|
_ => bail!("Either target and base or project and unit must be specified"),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(output) = &args.output {
|
|
||||||
run_oneshot(&args, output, target_path.as_deref(), base_path.as_deref())
|
|
||||||
} else {
|
|
||||||
run_interactive(args, target_path, base_path, project_config)
|
run_interactive(args, target_path, base_path, project_config)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_config_from_args(args: &Args) -> Result<(DiffObjConfig, MappingConfig)> {
|
fn build_config_from_args(args: &Args) -> Result<(DiffObjConfig, MappingConfig)> {
|
||||||
@ -194,28 +180,6 @@ fn build_config_from_args(args: &Args) -> Result<(DiffObjConfig, MappingConfig)>
|
|||||||
Ok((diff_config, mapping_config))
|
Ok((diff_config, mapping_config))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_oneshot(
|
|
||||||
args: &Args,
|
|
||||||
output: &Utf8PlatformPath,
|
|
||||||
target_path: Option<&Utf8PlatformPath>,
|
|
||||||
base_path: Option<&Utf8PlatformPath>,
|
|
||||||
) -> Result<()> {
|
|
||||||
let output_format = OutputFormat::from_option(args.format.as_deref())?;
|
|
||||||
let (diff_config, mapping_config) = build_config_from_args(args)?;
|
|
||||||
let target = target_path
|
|
||||||
.map(|p| obj::read::read(p.as_ref(), &diff_config).with_context(|| format!("Loading {p}")))
|
|
||||||
.transpose()?;
|
|
||||||
let base = base_path
|
|
||||||
.map(|p| obj::read::read(p.as_ref(), &diff_config).with_context(|| format!("Loading {p}")))
|
|
||||||
.transpose()?;
|
|
||||||
let result =
|
|
||||||
diff::diff_objs(target.as_ref(), base.as_ref(), None, &diff_config, &mapping_config)?;
|
|
||||||
let left = target.as_ref().and_then(|o| result.left.as_ref().map(|d| (o, d)));
|
|
||||||
let right = base.as_ref().and_then(|o| result.right.as_ref().map(|d| (o, d)));
|
|
||||||
write_output(&DiffResult::new(left, right), Some(output), output_format)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AppState {
|
pub struct AppState {
|
||||||
pub jobs: JobQueue,
|
pub jobs: JobQueue,
|
||||||
pub waker: Arc<TermWaker>,
|
pub waker: Arc<TermWaker>,
|
||||||
@ -378,10 +342,12 @@ fn run_interactive(
|
|||||||
};
|
};
|
||||||
if let (Some(project_dir), Some(project_config)) = (&state.project_dir, &state.project_config) {
|
if let (Some(project_dir), Some(project_config)) = (&state.project_dir, &state.project_config) {
|
||||||
let watch_patterns = project_config.build_watch_patterns()?;
|
let watch_patterns = project_config.build_watch_patterns()?;
|
||||||
|
let ignore_patterns = project_config.build_ignore_patterns()?;
|
||||||
state.watcher = Some(create_watcher(
|
state.watcher = Some(create_watcher(
|
||||||
state.modified.clone(),
|
state.modified.clone(),
|
||||||
project_dir.as_ref(),
|
project_dir.as_ref(),
|
||||||
build_globset(&watch_patterns)?,
|
build_globset(&watch_patterns)?,
|
||||||
|
build_globset(&ignore_patterns)?,
|
||||||
Waker::from(state.waker.clone()),
|
Waker::from(state.waker.clone()),
|
||||||
)?);
|
)?);
|
||||||
}
|
}
|
||||||
|
@ -132,12 +132,12 @@ itertools = { version = "0.14", default-features = false, features = ["use_alloc
|
|||||||
log = { version = "0.4", default-features = false, optional = true }
|
log = { version = "0.4", default-features = false, optional = true }
|
||||||
memmap2 = { version = "0.9", optional = true }
|
memmap2 = { version = "0.9", optional = true }
|
||||||
num-traits = { version = "0.2", default-features = false, optional = true }
|
num-traits = { version = "0.2", default-features = false, optional = true }
|
||||||
object = { git = "https://github.com/gimli-rs/object", rev = "16ff70aa6fbd97d6bb7b92375929f4d72414c32b", default-features = false, features = ["read_core", "elf", "coff"] }
|
object = { version = "0.37", default-features = false, features = ["read_core", "elf", "coff"] }
|
||||||
pbjson = { version = "0.8", default-features = false, optional = true }
|
pbjson = { version = "0.8", default-features = false, optional = true }
|
||||||
prost = { version = "0.14", default-features = false, features = ["derive"], optional = true }
|
prost = { version = "0.14", default-features = false, features = ["derive"], optional = true }
|
||||||
regex = { version = "1.11", default-features = false, features = [], optional = true }
|
regex = { version = "1.11", default-features = false, features = [], optional = true }
|
||||||
serde = { version = "1.0", default-features = false, features = ["derive"], optional = true }
|
serde = { version = "1.0", default-features = false, features = ["derive"], optional = true }
|
||||||
similar = { version = "2.7", default-features = false, features = ["hashbrown"], optional = true, git = "https://github.com/encounter/similar.git", branch = "no_std" }
|
similar = { git = "https://github.com/encounter/similar.git", branch = "no_std", default-features = false, features = ["hashbrown"], optional = true }
|
||||||
typed-path = { version = "0.11", default-features = false, optional = true }
|
typed-path = { version = "0.11", default-features = false, optional = true }
|
||||||
|
|
||||||
# config
|
# config
|
||||||
@ -146,7 +146,7 @@ semver = { version = "1.0", default-features = false, optional = true }
|
|||||||
serde_json = { version = "1.0", default-features = false, features = ["alloc"], optional = true }
|
serde_json = { version = "1.0", default-features = false, features = ["alloc"], optional = true }
|
||||||
|
|
||||||
# dwarf
|
# dwarf
|
||||||
gimli = { version = "0.32", default-features = false, features = ["read"], optional = true }
|
gimli = { git = "https://github.com/gimli-rs/gimli", rev = "7335f00e7c39fd501511584fefb0ba974117c950", default-features = false, features = ["read"], optional = true }
|
||||||
typed-arena = { version = "2.0", default-features = false, optional = true }
|
typed-arena = { version = "2.0", default-features = false, optional = true }
|
||||||
|
|
||||||
# ppc
|
# ppc
|
||||||
|
@ -1,165 +0,0 @@
|
|||||||
syntax = "proto3";
|
|
||||||
|
|
||||||
package objdiff.diff;
|
|
||||||
|
|
||||||
// A symbol
|
|
||||||
message Symbol {
|
|
||||||
// Name of the symbol
|
|
||||||
string name = 1;
|
|
||||||
// Demangled name of the symbol
|
|
||||||
optional string demangled_name = 2;
|
|
||||||
// Symbol address
|
|
||||||
uint64 address = 3;
|
|
||||||
// Symbol size
|
|
||||||
uint64 size = 4;
|
|
||||||
// Bitmask of SymbolFlag
|
|
||||||
uint32 flags = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Symbol visibility flags
|
|
||||||
enum SymbolFlag {
|
|
||||||
SYMBOL_NONE = 0;
|
|
||||||
SYMBOL_GLOBAL = 1;
|
|
||||||
SYMBOL_LOCAL = 2;
|
|
||||||
SYMBOL_WEAK = 4;
|
|
||||||
SYMBOL_COMMON = 8;
|
|
||||||
SYMBOL_HIDDEN = 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A single parsed instruction
|
|
||||||
message Instruction {
|
|
||||||
// Instruction address
|
|
||||||
uint64 address = 1;
|
|
||||||
// Instruction size
|
|
||||||
uint32 size = 2;
|
|
||||||
// Instruction opcode
|
|
||||||
uint32 opcode = 3;
|
|
||||||
// Instruction mnemonic
|
|
||||||
string mnemonic = 4;
|
|
||||||
// Instruction formatted string
|
|
||||||
string formatted = 5;
|
|
||||||
// Original (unsimplified) instruction string
|
|
||||||
optional string original = 6;
|
|
||||||
// Instruction arguments
|
|
||||||
repeated Argument arguments = 7;
|
|
||||||
// Instruction relocation
|
|
||||||
optional Relocation relocation = 8;
|
|
||||||
// Instruction branch destination
|
|
||||||
optional uint64 branch_dest = 9;
|
|
||||||
// Instruction line number
|
|
||||||
optional uint32 line_number = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
// An instruction argument
|
|
||||||
message Argument {
|
|
||||||
oneof value {
|
|
||||||
// Plain text
|
|
||||||
string plain_text = 1;
|
|
||||||
// Value
|
|
||||||
ArgumentValue argument = 2;
|
|
||||||
// Relocation
|
|
||||||
ArgumentRelocation relocation = 3;
|
|
||||||
// Branch destination
|
|
||||||
uint64 branch_dest = 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// An instruction argument value
|
|
||||||
message ArgumentValue {
|
|
||||||
oneof value {
|
|
||||||
// Signed integer
|
|
||||||
int64 signed = 1;
|
|
||||||
// Unsigned integer
|
|
||||||
uint64 unsigned = 2;
|
|
||||||
// Opaque value
|
|
||||||
string opaque = 3;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Marker type for relocation arguments
|
|
||||||
message ArgumentRelocation {
|
|
||||||
}
|
|
||||||
|
|
||||||
message Relocation {
|
|
||||||
uint32 type = 1;
|
|
||||||
string type_name = 2;
|
|
||||||
RelocationTarget target = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message RelocationTarget {
|
|
||||||
uint32 symbol_index = 1;
|
|
||||||
int64 addend = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message InstructionDiffRow {
|
|
||||||
DiffKind diff_kind = 1;
|
|
||||||
optional Instruction instruction = 2;
|
|
||||||
optional InstructionBranchFrom branch_from = 3;
|
|
||||||
optional InstructionBranchTo branch_to = 4;
|
|
||||||
repeated ArgumentDiff arg_diff = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ArgumentDiff {
|
|
||||||
optional uint32 diff_index = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum DiffKind {
|
|
||||||
DIFF_NONE = 0;
|
|
||||||
DIFF_REPLACE = 1;
|
|
||||||
DIFF_DELETE = 2;
|
|
||||||
DIFF_INSERT = 3;
|
|
||||||
DIFF_OP_MISMATCH = 4;
|
|
||||||
DIFF_ARG_MISMATCH = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
message InstructionBranchFrom {
|
|
||||||
repeated uint32 instruction_index = 1;
|
|
||||||
uint32 branch_index = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message InstructionBranchTo {
|
|
||||||
uint32 instruction_index = 1;
|
|
||||||
uint32 branch_index = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message SymbolDiff {
|
|
||||||
Symbol symbol = 1;
|
|
||||||
repeated InstructionDiffRow instruction_rows = 2;
|
|
||||||
optional float match_percent = 3;
|
|
||||||
// The symbol index in the _other_ object that this symbol was diffed against
|
|
||||||
optional uint32 target_symbol = 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
message DataDiff {
|
|
||||||
DiffKind kind = 1;
|
|
||||||
bytes data = 2;
|
|
||||||
// May be larger than data
|
|
||||||
uint64 size = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message SectionDiff {
|
|
||||||
string name = 1;
|
|
||||||
SectionKind kind = 2;
|
|
||||||
uint64 size = 3;
|
|
||||||
uint64 address = 4;
|
|
||||||
reserved 5;
|
|
||||||
repeated DataDiff data = 6;
|
|
||||||
optional float match_percent = 7;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum SectionKind {
|
|
||||||
SECTION_UNKNOWN = 0;
|
|
||||||
SECTION_TEXT = 1;
|
|
||||||
SECTION_DATA = 2;
|
|
||||||
SECTION_BSS = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
message ObjectDiff {
|
|
||||||
repeated SectionDiff sections = 1;
|
|
||||||
repeated SymbolDiff symbols = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
message DiffResult {
|
|
||||||
optional ObjectDiff left = 1;
|
|
||||||
optional ObjectDiff right = 2;
|
|
||||||
}
|
|
Binary file not shown.
@ -464,6 +464,22 @@ impl Arch for ArchArm {
|
|||||||
}
|
}
|
||||||
flags
|
flags
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn infer_function_size(
|
||||||
|
&self,
|
||||||
|
symbol: &Symbol,
|
||||||
|
section: &Section,
|
||||||
|
mut next_address: u64,
|
||||||
|
) -> Result<u64> {
|
||||||
|
// Trim any trailing 4-byte zeroes from the end (padding)
|
||||||
|
while next_address >= symbol.address + 4
|
||||||
|
&& let Some(data) = section.data_range(next_address - 4, 4)
|
||||||
|
&& data == [0u8; 4]
|
||||||
|
{
|
||||||
|
next_address -= 4;
|
||||||
|
}
|
||||||
|
Ok(next_address.saturating_sub(symbol.address))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
@ -6,6 +6,7 @@ use alloc::{
|
|||||||
vec::Vec,
|
vec::Vec,
|
||||||
};
|
};
|
||||||
use core::{
|
use core::{
|
||||||
|
any::Any,
|
||||||
ffi::CStr,
|
ffi::CStr,
|
||||||
fmt::{self, Debug},
|
fmt::{self, Debug},
|
||||||
};
|
};
|
||||||
@ -305,7 +306,7 @@ impl dyn Arch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Arch: Send + Sync + Debug {
|
pub trait Arch: Any + Debug + Send + Sync {
|
||||||
/// Finishes arch-specific initialization that must be done after sections have been combined.
|
/// Finishes arch-specific initialization that must be done after sections have been combined.
|
||||||
fn post_init(&mut self, _sections: &[Section], _symbols: &[Symbol]) {}
|
fn post_init(&mut self, _sections: &[Section], _symbols: &[Symbol]) {}
|
||||||
|
|
||||||
|
@ -1,242 +0,0 @@
|
|||||||
#![allow(clippy::needless_lifetimes)] // Generated serde code
|
|
||||||
|
|
||||||
use crate::{diff, obj};
|
|
||||||
|
|
||||||
// Protobuf diff types
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/objdiff.diff.rs"));
|
|
||||||
#[cfg(feature = "serde")]
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/objdiff.diff.serde.rs"));
|
|
||||||
|
|
||||||
impl DiffResult {
|
|
||||||
pub fn new(
|
|
||||||
_left: Option<(&obj::Object, &diff::ObjectDiff)>,
|
|
||||||
_right: Option<(&obj::Object, &diff::ObjectDiff)>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
// TODO
|
|
||||||
// left: left.map(|(obj, diff)| ObjectDiff::new(obj, diff)),
|
|
||||||
// right: right.map(|(obj, diff)| ObjectDiff::new(obj, diff)),
|
|
||||||
left: None,
|
|
||||||
right: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// impl ObjectDiff {
|
|
||||||
// pub fn new(obj: &obj::Object, diff: &diff::ObjectDiff) -> Self {
|
|
||||||
// Self {
|
|
||||||
// sections: diff
|
|
||||||
// .sections
|
|
||||||
// .iter()
|
|
||||||
// .enumerate()
|
|
||||||
// .map(|(i, d)| SectionDiff::new(obj, i, d))
|
|
||||||
// .collect(),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl SectionDiff {
|
|
||||||
// pub fn new(obj: &obj::Object, section_index: usize, section_diff: &diff::SectionDiff) -> Self {
|
|
||||||
// let section = &obj.sections[section_index];
|
|
||||||
// let symbols = section_diff.symbols.iter().map(|d| SymbolDiff::new(obj, d)).collect();
|
|
||||||
// let data = section_diff.data_diff.iter().map(|d| DataDiff::new(obj, d)).collect();
|
|
||||||
// // TODO: section_diff.reloc_diff
|
|
||||||
// Self {
|
|
||||||
// name: section.name.to_string(),
|
|
||||||
// kind: SectionKind::from(section.kind) as i32,
|
|
||||||
// size: section.size,
|
|
||||||
// address: section.address,
|
|
||||||
// symbols,
|
|
||||||
// data,
|
|
||||||
// match_percent: section_diff.match_percent,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl From<obj::SectionKind> for SectionKind {
|
|
||||||
// fn from(value: obj::SectionKind) -> Self {
|
|
||||||
// match value {
|
|
||||||
// obj::SectionKind::Code => SectionKind::SectionText,
|
|
||||||
// obj::SectionKind::Data => SectionKind::SectionData,
|
|
||||||
// obj::SectionKind::Bss => SectionKind::SectionBss,
|
|
||||||
// // TODO common
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl SymbolDiff {
|
|
||||||
// pub fn new(object: &obj::Object, symbol_diff: &diff::SymbolDiff) -> Self {
|
|
||||||
// let symbol = object.symbols[symbol_diff.symbol_index];
|
|
||||||
// let instructions = symbol_diff
|
|
||||||
// .instruction_rows
|
|
||||||
// .iter()
|
|
||||||
// .map(|ins_diff| InstructionDiff::new(object, ins_diff))
|
|
||||||
// .collect();
|
|
||||||
// Self {
|
|
||||||
// symbol: Some(Symbol::new(symbol)),
|
|
||||||
// instructions,
|
|
||||||
// match_percent: symbol_diff.match_percent,
|
|
||||||
// target: symbol_diff.target_symbol.map(SymbolRef::from),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl DataDiff {
|
|
||||||
// pub fn new(_object: &obj::Object, data_diff: &diff::DataDiff) -> Self {
|
|
||||||
// Self {
|
|
||||||
// kind: DiffKind::from(data_diff.kind) as i32,
|
|
||||||
// data: data_diff.data.clone(),
|
|
||||||
// size: data_diff.len as u64,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl Symbol {
|
|
||||||
// pub fn new(value: &ObjSymbol) -> Self {
|
|
||||||
// Self {
|
|
||||||
// name: value.name.to_string(),
|
|
||||||
// demangled_name: value.demangled_name.clone(),
|
|
||||||
// address: value.address,
|
|
||||||
// size: value.size,
|
|
||||||
// flags: symbol_flags(value.flags),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fn symbol_flags(value: ObjSymbolFlagSet) -> u32 {
|
|
||||||
// let mut flags = 0u32;
|
|
||||||
// if value.0.contains(ObjSymbolFlags::Global) {
|
|
||||||
// flags |= SymbolFlag::SymbolGlobal as u32;
|
|
||||||
// }
|
|
||||||
// if value.0.contains(ObjSymbolFlags::Local) {
|
|
||||||
// flags |= SymbolFlag::SymbolLocal as u32;
|
|
||||||
// }
|
|
||||||
// if value.0.contains(ObjSymbolFlags::Weak) {
|
|
||||||
// flags |= SymbolFlag::SymbolWeak as u32;
|
|
||||||
// }
|
|
||||||
// if value.0.contains(ObjSymbolFlags::Common) {
|
|
||||||
// flags |= SymbolFlag::SymbolCommon as u32;
|
|
||||||
// }
|
|
||||||
// if value.0.contains(ObjSymbolFlags::Hidden) {
|
|
||||||
// flags |= SymbolFlag::SymbolHidden as u32;
|
|
||||||
// }
|
|
||||||
// flags
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl Instruction {
|
|
||||||
// pub fn new(object: &obj::Object, instruction: &ObjIns) -> Self {
|
|
||||||
// Self {
|
|
||||||
// address: instruction.address,
|
|
||||||
// size: instruction.size as u32,
|
|
||||||
// opcode: instruction.op as u32,
|
|
||||||
// mnemonic: instruction.mnemonic.to_string(),
|
|
||||||
// formatted: instruction.formatted.clone(),
|
|
||||||
// arguments: instruction.args.iter().map(Argument::new).collect(),
|
|
||||||
// relocation: instruction.reloc.as_ref().map(|reloc| Relocation::new(object, reloc)),
|
|
||||||
// branch_dest: instruction.branch_dest,
|
|
||||||
// line_number: instruction.line,
|
|
||||||
// original: instruction.orig.clone(),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl Argument {
|
|
||||||
// pub fn new(value: &ObjInsArg) -> Self {
|
|
||||||
// Self {
|
|
||||||
// value: Some(match value {
|
|
||||||
// ObjInsArg::PlainText(s) => argument::Value::PlainText(s.to_string()),
|
|
||||||
// ObjInsArg::Arg(v) => argument::Value::Argument(ArgumentValue::new(v)),
|
|
||||||
// ObjInsArg::Reloc => argument::Value::Relocation(ArgumentRelocation {}),
|
|
||||||
// ObjInsArg::BranchDest(dest) => argument::Value::BranchDest(*dest),
|
|
||||||
// }),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl ArgumentValue {
|
|
||||||
// pub fn new(value: &ObjInsArgValue) -> Self {
|
|
||||||
// Self {
|
|
||||||
// value: Some(match value {
|
|
||||||
// ObjInsArgValue::Signed(v) => argument_value::Value::Signed(*v),
|
|
||||||
// ObjInsArgValue::Unsigned(v) => argument_value::Value::Unsigned(*v),
|
|
||||||
// ObjInsArgValue::Opaque(v) => argument_value::Value::Opaque(v.to_string()),
|
|
||||||
// }),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl Relocation {
|
|
||||||
// pub fn new(object: &obj::Object, reloc: &ObjReloc) -> Self {
|
|
||||||
// Self {
|
|
||||||
// r#type: match reloc.flags {
|
|
||||||
// object::RelocationFlags::Elf { r_type } => r_type,
|
|
||||||
// object::RelocationFlags::MachO { r_type, .. } => r_type as u32,
|
|
||||||
// object::RelocationFlags::Coff { typ } => typ as u32,
|
|
||||||
// object::RelocationFlags::Xcoff { r_rtype, .. } => r_rtype as u32,
|
|
||||||
// _ => unreachable!(),
|
|
||||||
// },
|
|
||||||
// type_name: object.arch.display_reloc(reloc.flags).into_owned(),
|
|
||||||
// target: Some(RelocationTarget {
|
|
||||||
// symbol: Some(Symbol::new(&reloc.target)),
|
|
||||||
// addend: reloc.addend,
|
|
||||||
// }),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl InstructionDiff {
|
|
||||||
// pub fn new(object: &obj::Object, instruction_diff: &ObjInsDiff) -> Self {
|
|
||||||
// Self {
|
|
||||||
// instruction: instruction_diff.ins.as_ref().map(|ins| Instruction::new(object, ins)),
|
|
||||||
// diff_kind: DiffKind::from(instruction_diff.kind) as i32,
|
|
||||||
// branch_from: instruction_diff.branch_from.as_ref().map(InstructionBranchFrom::new),
|
|
||||||
// branch_to: instruction_diff.branch_to.as_ref().map(InstructionBranchTo::new),
|
|
||||||
// arg_diff: instruction_diff.arg_diff.iter().map(ArgumentDiff::new).collect(),
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl ArgumentDiff {
|
|
||||||
// pub fn new(value: &Option<ObjInsArgDiff>) -> Self {
|
|
||||||
// Self { diff_index: value.as_ref().map(|v| v.idx as u32) }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl From<ObjInsDiffKind> for DiffKind {
|
|
||||||
// fn from(value: ObjInsDiffKind) -> Self {
|
|
||||||
// match value {
|
|
||||||
// ObjInsDiffKind::None => DiffKind::DiffNone,
|
|
||||||
// ObjInsDiffKind::OpMismatch => DiffKind::DiffOpMismatch,
|
|
||||||
// ObjInsDiffKind::ArgMismatch => DiffKind::DiffArgMismatch,
|
|
||||||
// ObjInsDiffKind::Replace => DiffKind::DiffReplace,
|
|
||||||
// ObjInsDiffKind::Delete => DiffKind::DiffDelete,
|
|
||||||
// ObjInsDiffKind::Insert => DiffKind::DiffInsert,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl From<ObjDataDiffKind> for DiffKind {
|
|
||||||
// fn from(value: ObjDataDiffKind) -> Self {
|
|
||||||
// match value {
|
|
||||||
// ObjDataDiffKind::None => DiffKind::DiffNone,
|
|
||||||
// ObjDataDiffKind::Replace => DiffKind::DiffReplace,
|
|
||||||
// ObjDataDiffKind::Delete => DiffKind::DiffDelete,
|
|
||||||
// ObjDataDiffKind::Insert => DiffKind::DiffInsert,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl InstructionBranchFrom {
|
|
||||||
// pub fn new(value: &ObjInsBranchFrom) -> Self {
|
|
||||||
// Self {
|
|
||||||
// instruction_index: value.ins_idx.iter().map(|&x| x as u32).collect(),
|
|
||||||
// branch_index: value.branch_idx as u32,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl InstructionBranchTo {
|
|
||||||
// pub fn new(value: &ObjInsBranchTo) -> Self {
|
|
||||||
// Self { instruction_index: value.ins_idx as u32, branch_index: value.branch_idx as u32 }
|
|
||||||
// }
|
|
||||||
// }
|
|
@ -1,3 +1 @@
|
|||||||
#[cfg(feature = "any-arch")]
|
|
||||||
pub mod diff;
|
|
||||||
pub mod report;
|
pub mod report;
|
||||||
|
@ -49,6 +49,7 @@ pub fn run_make(config: &BuildConfig, arg: &Utf8UnixPath) -> BuildStatus {
|
|||||||
};
|
};
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
let mut command = {
|
let mut command = {
|
||||||
|
use alloc::borrow::Cow;
|
||||||
use std::os::windows::process::CommandExt;
|
use std::os::windows::process::CommandExt;
|
||||||
|
|
||||||
let mut command = if config.selected_wsl_distro.is_some() {
|
let mut command = if config.selected_wsl_distro.is_some() {
|
||||||
@ -60,13 +61,17 @@ pub fn run_make(config: &BuildConfig, arg: &Utf8UnixPath) -> BuildStatus {
|
|||||||
// Strip distro root prefix \\wsl.localhost\{distro}
|
// Strip distro root prefix \\wsl.localhost\{distro}
|
||||||
let wsl_path_prefix = format!("\\\\wsl.localhost\\{}", distro);
|
let wsl_path_prefix = format!("\\\\wsl.localhost\\{}", distro);
|
||||||
let cwd = match cwd.strip_prefix(wsl_path_prefix) {
|
let cwd = match cwd.strip_prefix(wsl_path_prefix) {
|
||||||
Ok(new_cwd) => Utf8UnixPath::new("/").join(new_cwd.with_unix_encoding()),
|
// Convert to absolute Unix path
|
||||||
Err(_) => cwd.with_unix_encoding(),
|
Ok(new_cwd) => Cow::Owned(
|
||||||
|
Utf8UnixPath::new("/").join(new_cwd.with_unix_encoding()).into_string(),
|
||||||
|
),
|
||||||
|
// Otherwise, use the Windows path as is
|
||||||
|
Err(_) => Cow::Borrowed(cwd.as_str()),
|
||||||
};
|
};
|
||||||
|
|
||||||
command
|
command
|
||||||
.arg("--cd")
|
.arg("--cd")
|
||||||
.arg(cwd.as_str())
|
.arg::<&str>(cwd.as_ref())
|
||||||
.arg("-d")
|
.arg("-d")
|
||||||
.arg(distro)
|
.arg(distro)
|
||||||
.arg("--")
|
.arg("--")
|
||||||
|
@ -29,6 +29,7 @@ pub fn create_watcher(
|
|||||||
modified: Arc<AtomicBool>,
|
modified: Arc<AtomicBool>,
|
||||||
project_dir: &Path,
|
project_dir: &Path,
|
||||||
patterns: GlobSet,
|
patterns: GlobSet,
|
||||||
|
ignore_patterns: GlobSet,
|
||||||
waker: Waker,
|
waker: Waker,
|
||||||
) -> notify::Result<Watcher> {
|
) -> notify::Result<Watcher> {
|
||||||
let base_dir = fs::canonicalize(project_dir)?;
|
let base_dir = fs::canonicalize(project_dir)?;
|
||||||
@ -54,8 +55,8 @@ pub fn create_watcher(
|
|||||||
let Ok(path) = path.strip_prefix(&base_dir_clone) else {
|
let Ok(path) = path.strip_prefix(&base_dir_clone) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if patterns.is_match(path) {
|
if patterns.is_match(path) && !ignore_patterns.is_match(path) {
|
||||||
// log::info!("File modified: {}", path.display());
|
log::debug!("File modified: {}", path.display());
|
||||||
any_match = true;
|
any_match = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,8 @@ pub struct ProjectConfig {
|
|||||||
pub build_target: Option<bool>,
|
pub build_target: Option<bool>,
|
||||||
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
pub watch_patterns: Option<Vec<String>>,
|
pub watch_patterns: Option<Vec<String>>,
|
||||||
|
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
|
||||||
|
pub ignore_patterns: Option<Vec<String>>,
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
feature = "serde",
|
feature = "serde",
|
||||||
serde(alias = "objects", skip_serializing_if = "Option::is_none")
|
serde(alias = "objects", skip_serializing_if = "Option::is_none")
|
||||||
@ -66,7 +68,18 @@ impl ProjectConfig {
|
|||||||
.map(|s| Glob::new(s))
|
.map(|s| Glob::new(s))
|
||||||
.collect::<Result<Vec<Glob>, globset::Error>>()?
|
.collect::<Result<Vec<Glob>, globset::Error>>()?
|
||||||
} else {
|
} else {
|
||||||
DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect()
|
default_watch_patterns()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_ignore_patterns(&self) -> Result<Vec<Glob>, globset::Error> {
|
||||||
|
Ok(if let Some(ignore_patterns) = &self.ignore_patterns {
|
||||||
|
ignore_patterns
|
||||||
|
.iter()
|
||||||
|
.map(|s| Glob::new(s))
|
||||||
|
.collect::<Result<Vec<Glob>, globset::Error>>()?
|
||||||
|
} else {
|
||||||
|
default_ignore_patterns()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,10 +208,16 @@ pub const DEFAULT_WATCH_PATTERNS: &[&str] = &[
|
|||||||
"*.inc", "*.py", "*.yml", "*.txt", "*.json",
|
"*.inc", "*.py", "*.yml", "*.txt", "*.json",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
pub const DEFAULT_IGNORE_PATTERNS: &[&str] = &["build/**/*"];
|
||||||
|
|
||||||
pub fn default_watch_patterns() -> Vec<Glob> {
|
pub fn default_watch_patterns() -> Vec<Glob> {
|
||||||
DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect()
|
DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn default_ignore_patterns() -> Vec<Glob> {
|
||||||
|
DEFAULT_IGNORE_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[derive(Clone, Eq, PartialEq)]
|
#[derive(Clone, Eq, PartialEq)]
|
||||||
pub struct ProjectConfigInfo {
|
pub struct ProjectConfigInfo {
|
||||||
|
@ -25,6 +25,7 @@ wsl = []
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
|
argp = "0.4"
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
const_format = "0.2"
|
const_format = "0.2"
|
||||||
cwdemangle = "1.0"
|
cwdemangle = "1.0"
|
||||||
|
@ -16,8 +16,8 @@ use globset::Glob;
|
|||||||
use objdiff_core::{
|
use objdiff_core::{
|
||||||
build::watcher::{Watcher, create_watcher},
|
build::watcher::{Watcher, create_watcher},
|
||||||
config::{
|
config::{
|
||||||
DEFAULT_WATCH_PATTERNS, ProjectConfig, ProjectConfigInfo, ProjectObject, ScratchConfig,
|
ProjectConfig, ProjectConfigInfo, ProjectObject, ScratchConfig, build_globset,
|
||||||
build_globset, default_watch_patterns, path::platform_path_serde_option,
|
default_ignore_patterns, default_watch_patterns, path::platform_path_serde_option,
|
||||||
save_project_config,
|
save_project_config,
|
||||||
},
|
},
|
||||||
diff::DiffObjConfig,
|
diff::DiffObjConfig,
|
||||||
@ -219,6 +219,8 @@ pub struct AppConfig {
|
|||||||
#[serde(default = "default_watch_patterns")]
|
#[serde(default = "default_watch_patterns")]
|
||||||
pub watch_patterns: Vec<Glob>,
|
pub watch_patterns: Vec<Glob>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
pub ignore_patterns: Vec<Glob>,
|
||||||
|
#[serde(default)]
|
||||||
pub recent_projects: Vec<String>,
|
pub recent_projects: Vec<String>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub diff_obj_config: DiffObjConfig,
|
pub diff_obj_config: DiffObjConfig,
|
||||||
@ -239,7 +241,8 @@ impl Default for AppConfig {
|
|||||||
build_target: false,
|
build_target: false,
|
||||||
rebuild_on_changes: true,
|
rebuild_on_changes: true,
|
||||||
auto_update_check: true,
|
auto_update_check: true,
|
||||||
watch_patterns: DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect(),
|
watch_patterns: default_watch_patterns(),
|
||||||
|
ignore_patterns: default_ignore_patterns(),
|
||||||
recent_projects: vec![],
|
recent_projects: vec![],
|
||||||
diff_obj_config: Default::default(),
|
diff_obj_config: Default::default(),
|
||||||
}
|
}
|
||||||
@ -431,6 +434,7 @@ impl App {
|
|||||||
app_path: Option<PathBuf>,
|
app_path: Option<PathBuf>,
|
||||||
graphics_config: GraphicsConfig,
|
graphics_config: GraphicsConfig,
|
||||||
graphics_config_path: Option<PathBuf>,
|
graphics_config_path: Option<PathBuf>,
|
||||||
|
project_dir: Option<Utf8PlatformPathBuf>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Load previous app state (if any).
|
// Load previous app state (if any).
|
||||||
// Note that you must enable the `persistence` feature for this to work.
|
// Note that you must enable the `persistence` feature for this to work.
|
||||||
@ -440,7 +444,17 @@ impl App {
|
|||||||
app.appearance = appearance;
|
app.appearance = appearance;
|
||||||
}
|
}
|
||||||
if let Some(config) = deserialize_config(storage) {
|
if let Some(config) = deserialize_config(storage) {
|
||||||
let mut state = AppState { config, ..Default::default() };
|
let state = AppState { config, ..Default::default() };
|
||||||
|
app.state = Arc::new(RwLock::new(state));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
let mut state = app.state.write().unwrap();
|
||||||
|
if let Some(project_dir) = project_dir
|
||||||
|
&& state.config.project_dir.as_ref().is_none_or(|p| *p != project_dir)
|
||||||
|
{
|
||||||
|
state.set_project_dir(project_dir);
|
||||||
|
}
|
||||||
if state.config.project_dir.is_some() {
|
if state.config.project_dir.is_some() {
|
||||||
state.config_change = true;
|
state.config_change = true;
|
||||||
state.watcher_change = true;
|
state.watcher_change = true;
|
||||||
@ -449,8 +463,6 @@ impl App {
|
|||||||
state.queue_build = true;
|
state.queue_build = true;
|
||||||
}
|
}
|
||||||
app.view_state.config_state.queue_check_update = state.config.auto_update_check;
|
app.view_state.config_state.queue_check_update = state.config.auto_update_check;
|
||||||
app.state = Arc::new(RwLock::new(state));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
app.appearance.init_fonts(&cc.egui_ctx);
|
app.appearance.init_fonts(&cc.egui_ctx);
|
||||||
app.appearance.utc_offset = utc_offset;
|
app.appearance.utc_offset = utc_offset;
|
||||||
@ -551,11 +563,17 @@ impl App {
|
|||||||
if let Some(project_dir) = &state.config.project_dir {
|
if let Some(project_dir) = &state.config.project_dir {
|
||||||
match build_globset(&state.config.watch_patterns)
|
match build_globset(&state.config.watch_patterns)
|
||||||
.map_err(anyhow::Error::new)
|
.map_err(anyhow::Error::new)
|
||||||
.and_then(|globset| {
|
.and_then(|patterns| {
|
||||||
|
build_globset(&state.config.ignore_patterns)
|
||||||
|
.map(|ignore_patterns| (patterns, ignore_patterns))
|
||||||
|
.map_err(anyhow::Error::new)
|
||||||
|
})
|
||||||
|
.and_then(|(patterns, ignore_patterns)| {
|
||||||
create_watcher(
|
create_watcher(
|
||||||
self.modified.clone(),
|
self.modified.clone(),
|
||||||
project_dir.as_ref(),
|
project_dir.as_ref(),
|
||||||
globset,
|
patterns,
|
||||||
|
ignore_patterns,
|
||||||
egui_waker(ctx),
|
egui_waker(ctx),
|
||||||
)
|
)
|
||||||
.map_err(anyhow::Error::new)
|
.map_err(anyhow::Error::new)
|
||||||
|
63
objdiff-gui/src/argp_version.rs
Normal file
63
objdiff-gui/src/argp_version.rs
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// Originally from https://gist.github.com/suluke/e0c672492126be0a4f3b4f0e1115d77c
|
||||||
|
//! Extend `argp` to be better integrated with the `cargo` ecosystem
|
||||||
|
//!
|
||||||
|
//! For now, this only adds a --version/-V option which causes early-exit.
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
|
||||||
|
use argp::{EarlyExit, FromArgs, TopLevelCommand, parser::ParseGlobalOptions};
|
||||||
|
|
||||||
|
struct ArgsOrVersion<T>(T)
|
||||||
|
where T: FromArgs;
|
||||||
|
|
||||||
|
impl<T> TopLevelCommand for ArgsOrVersion<T> where T: FromArgs {}
|
||||||
|
|
||||||
|
impl<T> FromArgs for ArgsOrVersion<T>
|
||||||
|
where T: FromArgs
|
||||||
|
{
|
||||||
|
fn _from_args(
|
||||||
|
command_name: &[&str],
|
||||||
|
args: &[&OsStr],
|
||||||
|
parent: Option<&mut dyn ParseGlobalOptions>,
|
||||||
|
) -> Result<Self, EarlyExit> {
|
||||||
|
/// Also use argp for catching `--version`-only invocations
|
||||||
|
#[derive(FromArgs)]
|
||||||
|
struct Version {
|
||||||
|
/// Print version information and exit.
|
||||||
|
#[argp(switch, short = 'V')]
|
||||||
|
pub version: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
match Version::from_args(command_name, args) {
|
||||||
|
Ok(v) => {
|
||||||
|
if v.version {
|
||||||
|
println!(
|
||||||
|
"{} {}",
|
||||||
|
command_name.first().unwrap_or(&""),
|
||||||
|
env!("CARGO_PKG_VERSION"),
|
||||||
|
);
|
||||||
|
std::process::exit(0);
|
||||||
|
} else {
|
||||||
|
// Pass through empty arguments
|
||||||
|
T::_from_args(command_name, args, parent).map(Self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(exit) => match exit {
|
||||||
|
EarlyExit::Help(_help) => {
|
||||||
|
// TODO: Chain help info from Version
|
||||||
|
// For now, we just put the switch on T as well
|
||||||
|
T::from_args(command_name, &["--help"]).map(Self)
|
||||||
|
}
|
||||||
|
EarlyExit::Err(_) => T::_from_args(command_name, args, parent).map(Self),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a `FromArgs` type from the current process’s `env::args`.
|
||||||
|
///
|
||||||
|
/// This function will exit early from the current process if argument parsing was unsuccessful or if information like `--help` was requested.
|
||||||
|
/// Error messages will be printed to stderr, and `--help` output to stdout.
|
||||||
|
pub fn from_env<T>() -> T
|
||||||
|
where T: TopLevelCommand {
|
||||||
|
argp::parse_args_or_exit::<ArgsOrVersion<T>>(argp::DEFAULT).0
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use globset::Glob;
|
use globset::Glob;
|
||||||
use objdiff_core::config::{DEFAULT_WATCH_PATTERNS, try_project_config};
|
use objdiff_core::config::{default_ignore_patterns, default_watch_patterns, try_project_config};
|
||||||
use typed_path::{Utf8UnixComponent, Utf8UnixPath};
|
use typed_path::{Utf8UnixComponent, Utf8UnixPath};
|
||||||
|
|
||||||
use crate::app::{AppState, ObjectConfig};
|
use crate::app::{AppState, ObjectConfig};
|
||||||
@ -96,8 +96,15 @@ pub fn load_project_config(state: &mut AppState) -> Result<()> {
|
|||||||
.map(|s| Glob::new(s))
|
.map(|s| Glob::new(s))
|
||||||
.collect::<Result<Vec<Glob>, globset::Error>>()?;
|
.collect::<Result<Vec<Glob>, globset::Error>>()?;
|
||||||
} else {
|
} else {
|
||||||
state.config.watch_patterns =
|
state.config.watch_patterns = default_watch_patterns();
|
||||||
DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect();
|
}
|
||||||
|
if let Some(ignore_patterns) = &project_config.ignore_patterns {
|
||||||
|
state.config.ignore_patterns = ignore_patterns
|
||||||
|
.iter()
|
||||||
|
.map(|s| Glob::new(s))
|
||||||
|
.collect::<Result<Vec<Glob>, globset::Error>>()?;
|
||||||
|
} else {
|
||||||
|
state.config.ignore_patterns = default_ignore_patterns();
|
||||||
}
|
}
|
||||||
state.watcher_change = true;
|
state.watcher_change = true;
|
||||||
state.objects = project_config
|
state.objects = project_config
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
mod app_config;
|
mod app_config;
|
||||||
|
mod argp_version;
|
||||||
mod config;
|
mod config;
|
||||||
mod fonts;
|
mod fonts;
|
||||||
mod hotkeys;
|
mod hotkeys;
|
||||||
@ -11,19 +12,83 @@ mod update;
|
|||||||
mod views;
|
mod views;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
|
ffi::OsStr,
|
||||||
|
fmt::Display,
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
process::ExitCode,
|
process::ExitCode,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
|
str::FromStr,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Result, ensure};
|
use anyhow::{Result, ensure};
|
||||||
|
use argp::{FromArgValue, FromArgs};
|
||||||
use cfg_if::cfg_if;
|
use cfg_if::cfg_if;
|
||||||
|
use objdiff_core::config::path::check_path_buf;
|
||||||
use time::UtcOffset;
|
use time::UtcOffset;
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::{EnvFilter, filter::LevelFilter};
|
||||||
|
use typed_path::Utf8PlatformPathBuf;
|
||||||
|
|
||||||
use crate::views::graphics::{GraphicsBackend, GraphicsConfig, load_graphics_config};
|
use crate::views::graphics::{GraphicsBackend, GraphicsConfig, load_graphics_config};
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||||
|
enum LogLevel {
|
||||||
|
Error,
|
||||||
|
Warn,
|
||||||
|
Info,
|
||||||
|
Debug,
|
||||||
|
Trace,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for LogLevel {
|
||||||
|
type Err = ();
|
||||||
|
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
Ok(match s {
|
||||||
|
"error" => Self::Error,
|
||||||
|
"warn" => Self::Warn,
|
||||||
|
"info" => Self::Info,
|
||||||
|
"debug" => Self::Debug,
|
||||||
|
"trace" => Self::Trace,
|
||||||
|
_ => return Err(()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for LogLevel {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str(match self {
|
||||||
|
LogLevel::Error => "error",
|
||||||
|
LogLevel::Warn => "warn",
|
||||||
|
LogLevel::Info => "info",
|
||||||
|
LogLevel::Debug => "debug",
|
||||||
|
LogLevel::Trace => "trace",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromArgValue for LogLevel {
|
||||||
|
fn from_arg_value(value: &OsStr) -> Result<Self, String> {
|
||||||
|
String::from_arg_value(value)
|
||||||
|
.and_then(|s| Self::from_str(&s).map_err(|_| "Invalid log level".to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(FromArgs, PartialEq, Debug)]
|
||||||
|
/// A local diffing tool for decompilation projects.
|
||||||
|
struct TopLevel {
|
||||||
|
#[argp(option, short = 'L')]
|
||||||
|
/// Minimum logging level. (Default: info)
|
||||||
|
/// Possible values: error, warn, info, debug, trace
|
||||||
|
log_level: Option<LogLevel>,
|
||||||
|
#[argp(option, short = 'p')]
|
||||||
|
/// Path to the project directory.
|
||||||
|
project_dir: Option<PathBuf>,
|
||||||
|
/// Print version information and exit.
|
||||||
|
#[argp(switch, short = 'V')]
|
||||||
|
version: bool,
|
||||||
|
}
|
||||||
|
|
||||||
fn load_icon() -> Result<egui::IconData> {
|
fn load_icon() -> Result<egui::IconData> {
|
||||||
let decoder = png::Decoder::new(include_bytes!("../assets/icon_64.png").as_ref());
|
let decoder = png::Decoder::new(include_bytes!("../assets/icon_64.png").as_ref());
|
||||||
let mut reader = decoder.read_info()?;
|
let mut reader = decoder.read_info()?;
|
||||||
@ -38,23 +103,63 @@ fn load_icon() -> Result<egui::IconData> {
|
|||||||
const APP_NAME: &str = "objdiff";
|
const APP_NAME: &str = "objdiff";
|
||||||
|
|
||||||
fn main() -> ExitCode {
|
fn main() -> ExitCode {
|
||||||
// Log to stdout (if you run with `RUST_LOG=debug`).
|
let args: TopLevel = argp_version::from_env();
|
||||||
tracing_subscriber::fmt()
|
let builder = tracing_subscriber::fmt();
|
||||||
|
if let Some(level) = args.log_level {
|
||||||
|
builder
|
||||||
|
.with_max_level(match level {
|
||||||
|
LogLevel::Error => LevelFilter::ERROR,
|
||||||
|
LogLevel::Warn => LevelFilter::WARN,
|
||||||
|
LogLevel::Info => LevelFilter::INFO,
|
||||||
|
LogLevel::Debug => LevelFilter::DEBUG,
|
||||||
|
LogLevel::Trace => LevelFilter::TRACE,
|
||||||
|
})
|
||||||
|
.init();
|
||||||
|
} else {
|
||||||
|
builder
|
||||||
.with_env_filter(
|
.with_env_filter(
|
||||||
EnvFilter::builder()
|
EnvFilter::builder()
|
||||||
// Default to info level
|
// Default to info level
|
||||||
.with_default_directive(tracing_subscriber::filter::LevelFilter::INFO.into())
|
.with_default_directive(LevelFilter::INFO.into())
|
||||||
.from_env_lossy()
|
.from_env_lossy()
|
||||||
// This module is noisy at info level
|
// This module is noisy at info level
|
||||||
.add_directive("wgpu_core::device::resource=warn".parse().unwrap()),
|
.add_directive("wgpu_core::device::resource=warn".parse().unwrap()),
|
||||||
)
|
)
|
||||||
.init();
|
.init();
|
||||||
|
}
|
||||||
|
|
||||||
// Because localtime_r is unsound in multithreaded apps,
|
// Because localtime_r is unsound in multithreaded apps,
|
||||||
// we must call this before initializing eframe.
|
// we must call this before initializing eframe.
|
||||||
// https://github.com/time-rs/time/issues/293
|
// https://github.com/time-rs/time/issues/293
|
||||||
let utc_offset = UtcOffset::current_local_offset().unwrap_or(UtcOffset::UTC);
|
let utc_offset = UtcOffset::current_local_offset().unwrap_or(UtcOffset::UTC);
|
||||||
|
|
||||||
|
// Resolve project directory if provided
|
||||||
|
let project_dir = if let Some(path) = args.project_dir {
|
||||||
|
match path.canonicalize() {
|
||||||
|
Ok(path) => {
|
||||||
|
// Ensure the path is a directory
|
||||||
|
if path.is_dir() {
|
||||||
|
match check_path_buf(path) {
|
||||||
|
Ok(path) => Some(path),
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to convert project directory to UTF-8 path: {}", e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::error!("Project directory is not a directory: {}", path.display());
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to canonicalize project directory: {}", e);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
let app_path = std::env::current_exe().ok();
|
let app_path = std::env::current_exe().ok();
|
||||||
let exec_path: Rc<Mutex<Option<PathBuf>>> = Rc::new(Mutex::new(None));
|
let exec_path: Rc<Mutex<Option<PathBuf>>> = Rc::new(Mutex::new(None));
|
||||||
let mut native_options = eframe::NativeOptions {
|
let mut native_options = eframe::NativeOptions {
|
||||||
@ -113,6 +218,7 @@ fn main() -> ExitCode {
|
|||||||
app_path.clone(),
|
app_path.clone(),
|
||||||
graphics_config.clone(),
|
graphics_config.clone(),
|
||||||
graphics_config_path.clone(),
|
graphics_config_path.clone(),
|
||||||
|
project_dir.clone(),
|
||||||
) {
|
) {
|
||||||
eframe_error = Some(e);
|
eframe_error = Some(e);
|
||||||
}
|
}
|
||||||
@ -139,6 +245,7 @@ fn main() -> ExitCode {
|
|||||||
app_path.clone(),
|
app_path.clone(),
|
||||||
graphics_config.clone(),
|
graphics_config.clone(),
|
||||||
graphics_config_path.clone(),
|
graphics_config_path.clone(),
|
||||||
|
project_dir.clone(),
|
||||||
) {
|
) {
|
||||||
eframe_error = Some(e);
|
eframe_error = Some(e);
|
||||||
} else {
|
} else {
|
||||||
@ -161,6 +268,7 @@ fn main() -> ExitCode {
|
|||||||
app_path,
|
app_path,
|
||||||
graphics_config,
|
graphics_config,
|
||||||
graphics_config_path,
|
graphics_config_path,
|
||||||
|
project_dir,
|
||||||
) {
|
) {
|
||||||
eframe_error = Some(e);
|
eframe_error = Some(e);
|
||||||
} else {
|
} else {
|
||||||
@ -204,6 +312,7 @@ fn run_eframe(
|
|||||||
app_path: Option<PathBuf>,
|
app_path: Option<PathBuf>,
|
||||||
graphics_config: GraphicsConfig,
|
graphics_config: GraphicsConfig,
|
||||||
graphics_config_path: Option<PathBuf>,
|
graphics_config_path: Option<PathBuf>,
|
||||||
|
project_dir: Option<Utf8PlatformPathBuf>,
|
||||||
) -> Result<(), eframe::Error> {
|
) -> Result<(), eframe::Error> {
|
||||||
eframe::run_native(
|
eframe::run_native(
|
||||||
APP_NAME,
|
APP_NAME,
|
||||||
@ -216,6 +325,7 @@ fn run_eframe(
|
|||||||
app_path,
|
app_path,
|
||||||
graphics_config,
|
graphics_config,
|
||||||
graphics_config_path,
|
graphics_config_path,
|
||||||
|
project_dir,
|
||||||
)))
|
)))
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
@ -11,6 +11,7 @@ pub struct Appearance {
|
|||||||
pub ui_font: FontId,
|
pub ui_font: FontId,
|
||||||
pub code_font: FontId,
|
pub code_font: FontId,
|
||||||
pub diff_colors: Vec<Color32>,
|
pub diff_colors: Vec<Color32>,
|
||||||
|
pub diff_bg_color: Option<Color32>,
|
||||||
pub theme: egui::Theme,
|
pub theme: egui::Theme,
|
||||||
|
|
||||||
// Applied by theme
|
// Applied by theme
|
||||||
@ -67,6 +68,7 @@ impl Default for Appearance {
|
|||||||
replace_color: Color32::LIGHT_BLUE,
|
replace_color: Color32::LIGHT_BLUE,
|
||||||
insert_color: Color32::GREEN,
|
insert_color: Color32::GREEN,
|
||||||
delete_color: Color32::from_rgb(200, 40, 41),
|
delete_color: Color32::from_rgb(200, 40, 41),
|
||||||
|
diff_bg_color: None,
|
||||||
utc_offset: UtcOffset::UTC,
|
utc_offset: UtcOffset::UTC,
|
||||||
fonts: FontState::default(),
|
fonts: FontState::default(),
|
||||||
next_ui_font: None,
|
next_ui_font: None,
|
||||||
@ -103,6 +105,9 @@ impl Appearance {
|
|||||||
match self.theme {
|
match self.theme {
|
||||||
egui::Theme::Dark => {
|
egui::Theme::Dark => {
|
||||||
style.visuals = egui::Visuals::dark();
|
style.visuals = egui::Visuals::dark();
|
||||||
|
if let Some(diff_bg_color) = self.diff_bg_color {
|
||||||
|
style.visuals.faint_bg_color = diff_bg_color;
|
||||||
|
}
|
||||||
self.text_color = Color32::GRAY;
|
self.text_color = Color32::GRAY;
|
||||||
self.emphasized_text_color = Color32::LIGHT_GRAY;
|
self.emphasized_text_color = Color32::LIGHT_GRAY;
|
||||||
self.deemphasized_text_color = Color32::DARK_GRAY;
|
self.deemphasized_text_color = Color32::DARK_GRAY;
|
||||||
@ -114,6 +119,9 @@ impl Appearance {
|
|||||||
}
|
}
|
||||||
egui::Theme::Light => {
|
egui::Theme::Light => {
|
||||||
style.visuals = egui::Visuals::light();
|
style.visuals = egui::Visuals::light();
|
||||||
|
if let Some(diff_bg_color) = self.diff_bg_color {
|
||||||
|
style.visuals.faint_bg_color = diff_bg_color;
|
||||||
|
}
|
||||||
self.text_color = Color32::GRAY;
|
self.text_color = Color32::GRAY;
|
||||||
self.emphasized_text_color = Color32::DARK_GRAY;
|
self.emphasized_text_color = Color32::DARK_GRAY;
|
||||||
self.deemphasized_text_color = Color32::LIGHT_GRAY;
|
self.deemphasized_text_color = Color32::LIGHT_GRAY;
|
||||||
@ -294,6 +302,21 @@ pub fn appearance_window(ctx: &egui::Context, show: &mut bool, appearance: &mut
|
|||||||
appearance,
|
appearance,
|
||||||
);
|
);
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
ui.horizontal(|ui| {
|
||||||
|
ui.label("Diff fill color:");
|
||||||
|
let mut diff_bg_color =
|
||||||
|
appearance.diff_bg_color.unwrap_or_else(|| match appearance.theme {
|
||||||
|
egui::Theme::Dark => egui::Visuals::dark().faint_bg_color,
|
||||||
|
egui::Theme::Light => egui::Visuals::light().faint_bg_color,
|
||||||
|
});
|
||||||
|
if ui.color_edit_button_srgba(&mut diff_bg_color).changed() {
|
||||||
|
appearance.diff_bg_color = Some(diff_bg_color);
|
||||||
|
}
|
||||||
|
if ui.button("Reset").clicked() {
|
||||||
|
appearance.diff_bg_color = None;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ui.separator();
|
||||||
ui.label("Diff colors:");
|
ui.label("Diff colors:");
|
||||||
if ui.button("Reset").clicked() {
|
if ui.button("Reset").clicked() {
|
||||||
appearance.diff_colors = DEFAULT_COLOR_ROTATION.to_vec();
|
appearance.diff_colors = DEFAULT_COLOR_ROTATION.to_vec();
|
||||||
|
@ -10,7 +10,7 @@ use egui::{
|
|||||||
};
|
};
|
||||||
use globset::Glob;
|
use globset::Glob;
|
||||||
use objdiff_core::{
|
use objdiff_core::{
|
||||||
config::{DEFAULT_WATCH_PATTERNS, path::check_path_buf},
|
config::{default_ignore_patterns, default_watch_patterns, path::check_path_buf},
|
||||||
diff::{
|
diff::{
|
||||||
CONFIG_GROUPS, ConfigEnum, ConfigEnumVariantInfo, ConfigPropertyId, ConfigPropertyKind,
|
CONFIG_GROUPS, ConfigEnum, ConfigEnumVariantInfo, ConfigPropertyId, ConfigPropertyKind,
|
||||||
ConfigPropertyValue,
|
ConfigPropertyValue,
|
||||||
@ -41,6 +41,7 @@ pub struct ConfigViewState {
|
|||||||
pub build_running: bool,
|
pub build_running: bool,
|
||||||
pub queue_build: bool,
|
pub queue_build: bool,
|
||||||
pub watch_pattern_text: String,
|
pub watch_pattern_text: String,
|
||||||
|
pub ignore_pattern_text: String,
|
||||||
pub object_search: String,
|
pub object_search: String,
|
||||||
pub filter_diffable: bool,
|
pub filter_diffable: bool,
|
||||||
pub filter_incomplete: bool,
|
pub filter_incomplete: bool,
|
||||||
@ -790,20 +791,49 @@ fn split_obj_config_ui(
|
|||||||
state.watcher_change = true;
|
state.watcher_change = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
state.watcher_change |= patterns_ui(
|
||||||
|
ui,
|
||||||
|
"File patterns",
|
||||||
|
&mut state.config.watch_patterns,
|
||||||
|
&mut config_state.watch_pattern_text,
|
||||||
|
appearance,
|
||||||
|
state.project_config_info.is_some(),
|
||||||
|
default_watch_patterns,
|
||||||
|
);
|
||||||
|
state.watcher_change |= patterns_ui(
|
||||||
|
ui,
|
||||||
|
"Ignore patterns",
|
||||||
|
&mut state.config.ignore_patterns,
|
||||||
|
&mut config_state.ignore_pattern_text,
|
||||||
|
appearance,
|
||||||
|
state.project_config_info.is_some(),
|
||||||
|
default_ignore_patterns,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn patterns_ui(
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
text: &str,
|
||||||
|
patterns: &mut Vec<Glob>,
|
||||||
|
pattern_text: &mut String,
|
||||||
|
appearance: &Appearance,
|
||||||
|
has_project_config: bool,
|
||||||
|
on_reset: impl FnOnce() -> Vec<Glob>,
|
||||||
|
) -> bool {
|
||||||
|
let mut change = false;
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label(RichText::new("File patterns").color(appearance.text_color));
|
ui.label(RichText::new(text).color(appearance.text_color));
|
||||||
if ui
|
if ui
|
||||||
.add_enabled(state.project_config_info.is_none(), egui::Button::new("Reset"))
|
.add_enabled(!has_project_config, egui::Button::new("Reset"))
|
||||||
.on_disabled_hover_text(CONFIG_DISABLED_TEXT)
|
.on_disabled_hover_text(CONFIG_DISABLED_TEXT)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
state.config.watch_patterns =
|
*patterns = on_reset();
|
||||||
DEFAULT_WATCH_PATTERNS.iter().map(|s| Glob::new(s).unwrap()).collect();
|
change = true;
|
||||||
state.watcher_change = true;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
let mut remove_at: Option<usize> = None;
|
let mut remove_at: Option<usize> = None;
|
||||||
for (idx, glob) in state.config.watch_patterns.iter().enumerate() {
|
for (idx, glob) in patterns.iter().enumerate() {
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label(
|
ui.label(
|
||||||
RichText::new(glob.to_string())
|
RichText::new(glob.to_string())
|
||||||
@ -811,7 +841,7 @@ fn split_obj_config_ui(
|
|||||||
.family(FontFamily::Monospace),
|
.family(FontFamily::Monospace),
|
||||||
);
|
);
|
||||||
if ui
|
if ui
|
||||||
.add_enabled(state.project_config_info.is_none(), egui::Button::new("-").small())
|
.add_enabled(!has_project_config, egui::Button::new("-").small())
|
||||||
.on_disabled_hover_text(CONFIG_DISABLED_TEXT)
|
.on_disabled_hover_text(CONFIG_DISABLED_TEXT)
|
||||||
.clicked()
|
.clicked()
|
||||||
{
|
{
|
||||||
@ -820,26 +850,27 @@ fn split_obj_config_ui(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if let Some(idx) = remove_at {
|
if let Some(idx) = remove_at {
|
||||||
state.config.watch_patterns.remove(idx);
|
patterns.remove(idx);
|
||||||
state.watcher_change = true;
|
change = true;
|
||||||
}
|
}
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.add_enabled(
|
ui.add_enabled(
|
||||||
state.project_config_info.is_none(),
|
!has_project_config,
|
||||||
egui::TextEdit::singleline(&mut config_state.watch_pattern_text).desired_width(100.0),
|
egui::TextEdit::singleline(pattern_text).desired_width(100.0),
|
||||||
)
|
)
|
||||||
.on_disabled_hover_text(CONFIG_DISABLED_TEXT);
|
.on_disabled_hover_text(CONFIG_DISABLED_TEXT);
|
||||||
if ui
|
if ui
|
||||||
.add_enabled(state.project_config_info.is_none(), egui::Button::new("+").small())
|
.add_enabled(!has_project_config, egui::Button::new("+").small())
|
||||||
.on_disabled_hover_text(CONFIG_DISABLED_TEXT)
|
.on_disabled_hover_text(CONFIG_DISABLED_TEXT)
|
||||||
.clicked()
|
.clicked()
|
||||||
&& let Ok(glob) = Glob::new(&config_state.watch_pattern_text)
|
&& let Ok(glob) = Glob::new(pattern_text)
|
||||||
{
|
{
|
||||||
state.config.watch_patterns.push(glob);
|
patterns.push(glob);
|
||||||
state.watcher_change = true;
|
change = true;
|
||||||
config_state.watch_pattern_text.clear();
|
pattern_text.clear();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
change
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn arch_config_window(
|
pub fn arch_config_window(
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
|
use core::any::Any;
|
||||||
|
|
||||||
use egui::ScrollArea;
|
use egui::ScrollArea;
|
||||||
use objdiff_core::{
|
use objdiff_core::{arch::ppc::ExceptionInfo, obj::Object};
|
||||||
arch::ppc::ExceptionInfo,
|
|
||||||
obj::{Object, Symbol},
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::views::{appearance::Appearance, function_diff::FunctionDiffContext};
|
use crate::views::{appearance::Appearance, function_diff::FunctionDiffContext};
|
||||||
|
|
||||||
@ -26,19 +25,19 @@ fn decode_extab(extab: &ExceptionInfo) -> String {
|
|||||||
text
|
text
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_extab_entry<'a>(_obj: &'a Object, _symbol: &Symbol) -> Option<&'a ExceptionInfo> {
|
fn find_extab_entry(obj: &Object, symbol_index: usize) -> Option<&ExceptionInfo> {
|
||||||
// TODO
|
(obj.arch.as_ref() as &dyn Any)
|
||||||
// obj.arch.ppc().and_then(|ppc| ppc.extab_for_symbol(symbol))
|
.downcast_ref::<objdiff_core::arch::ppc::ArchPpc>()
|
||||||
None
|
.and_then(|ppc| ppc.extab_for_symbol(symbol_index))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn extab_text_ui(
|
fn extab_text_ui(
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
ctx: FunctionDiffContext<'_>,
|
ctx: FunctionDiffContext<'_>,
|
||||||
symbol: &Symbol,
|
symbol_index: usize,
|
||||||
appearance: &Appearance,
|
appearance: &Appearance,
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if let Some(extab_entry) = find_extab_entry(ctx.obj, symbol) {
|
if let Some(extab_entry) = find_extab_entry(ctx.obj, symbol_index) {
|
||||||
let text = decode_extab(extab_entry);
|
let text = decode_extab(extab_entry);
|
||||||
ui.colored_label(appearance.replace_color, &text);
|
ui.colored_label(appearance.replace_color, &text);
|
||||||
return Some(());
|
return Some(());
|
||||||
@ -58,10 +57,8 @@ pub(crate) fn extab_ui(
|
|||||||
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
ui.style_mut().override_text_style = Some(egui::TextStyle::Monospace);
|
||||||
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
ui.style_mut().wrap_mode = Some(egui::TextWrapMode::Extend);
|
||||||
|
|
||||||
if let Some(symbol) =
|
if let Some(symbol_index) = ctx.symbol_ref {
|
||||||
ctx.symbol_ref.and_then(|symbol_ref| ctx.obj.symbols.get(symbol_ref))
|
extab_text_ui(ui, ctx, symbol_index, appearance);
|
||||||
{
|
|
||||||
extab_text_ui(ui, ctx, symbol, appearance);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -142,6 +142,11 @@ impl DiffViewState {
|
|||||||
JobResult::ObjDiff(result) => {
|
JobResult::ObjDiff(result) => {
|
||||||
self.build = take(result);
|
self.build = take(result);
|
||||||
|
|
||||||
|
// Clear reload flag so that we don't reload the view immediately
|
||||||
|
if let Ok(mut state) = state.write() {
|
||||||
|
state.queue_reload = false;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: where should this go?
|
// TODO: where should this go?
|
||||||
if let Some(result) = self.post_build_nav.take() {
|
if let Some(result) = self.post_build_nav.take() {
|
||||||
self.current_view = result.view;
|
self.current_view = result.view;
|
||||||
|
4
objdiff-wasm/package-lock.json
generated
4
objdiff-wasm/package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "objdiff-wasm",
|
"name": "objdiff-wasm",
|
||||||
"version": "3.0.0-beta.14",
|
"version": "3.0.0",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "objdiff-wasm",
|
"name": "objdiff-wasm",
|
||||||
"version": "3.0.0-beta.14",
|
"version": "3.0.0",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@biomejs/biome": "^1.9.3",
|
"@biomejs/biome": "^1.9.3",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "objdiff-wasm",
|
"name": "objdiff-wasm",
|
||||||
"version": "3.0.0-beta.14",
|
"version": "3.0.0",
|
||||||
"description": "A local diffing tool for decompilation projects.",
|
"description": "A local diffing tool for decompilation projects.",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Luke Street",
|
"name": "Luke Street",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user