Compare commits

...

6 Commits

Author SHA1 Message Date
Antonio Scandurra
a7ed4de96c Update status 2025-03-27 17:34:22 +01:00
Antonio Scandurra
dae295fc72 Reuse the same BufferDiffs instead of always creating new ones 2025-03-27 16:37:51 +01:00
Antonio Scandurra
e1ed35377a Start on a new ThreadDiff primitive 2025-03-27 16:29:47 +01:00
Antonio Scandurra
c707ec1c24 Add a new GitStoreStatus::entries method 2025-03-27 15:02:07 +01:00
Antonio Scandurra
a5677a1e93 Fix diffing checkpoints not returning a newline 2025-03-27 15:01:47 +01:00
Antonio Scandurra
eba6f443fd Introduce a DiffSource trait for ProjectDiff 2025-03-27 10:53:26 +01:00
10 changed files with 583 additions and 158 deletions

149
Cargo.lock generated
View File

@@ -86,7 +86,7 @@ version = "0.25.1-dev"
source = "git+https://github.com/zed-industries/alacritty.git?branch=add-hush-login-flag#828457c9ff1f7ea0a0469337cc8a37ee3a1b0590"
dependencies = [
"base64 0.22.1",
"bitflags 2.9.0",
"bitflags 2.8.0",
"home",
"libc",
"log",
@@ -128,7 +128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed7572b7ba83a31e20d1b48970ee402d2e3e0537dcfe0a3ff4d6eb7508617d43"
dependencies = [
"alsa-sys",
"bitflags 2.9.0",
"bitflags 2.8.0",
"cfg-if",
"libc",
]
@@ -453,6 +453,7 @@ dependencies = [
"assistant_slash_command",
"assistant_tool",
"async-watch",
"buffer_diff",
"chrono",
"client",
"clock",
@@ -1880,10 +1881,10 @@ version = "0.69.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"cexpr",
"clang-sys",
"itertools 0.10.5",
"itertools 0.12.1",
"lazy_static",
"lazycell",
"log",
@@ -1903,10 +1904,10 @@ version = "0.70.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"cexpr",
"clang-sys",
"itertools 0.10.5",
"itertools 0.12.1",
"log",
"prettyplease",
"proc-macro2",
@@ -1961,9 +1962,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.9.0"
version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36"
dependencies = [
"serde",
]
@@ -1993,7 +1994,7 @@ source = "git+https://github.com/kvark/blade?rev=b16f5c7bd873c7126f48c82c39e7ae6
dependencies = [
"ash",
"ash-window",
"bitflags 2.9.0",
"bitflags 2.8.0",
"bytemuck",
"codespan-reporting",
"glow",
@@ -2041,9 +2042,9 @@ dependencies = [
[[package]]
name = "blake3"
version = "1.7.0"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b17679a8d69b6d7fd9cd9801a536cec9fa5e5970b69f9d4747f70b39b031f5e7"
checksum = "675f87afced0413c9bb02843499dbbd3882a237645883f71a2b59644a6d2f753"
dependencies = [
"arrayref",
"arrayvec",
@@ -2322,7 +2323,7 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"log",
"polling",
"rustix",
@@ -2828,7 +2829,7 @@ version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f79398230a6e2c08f5c9760610eb6924b52aa9e7950a619602baba59dcbbdbb2"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"block",
"cocoa-foundation 0.2.0",
"core-foundation 0.10.0",
@@ -2858,7 +2859,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e14045fb83be07b5acf1c0884b2180461635b433455fa35d1cd6f17f1450679d"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"block",
"core-foundation 0.10.0",
"core-graphics-types 0.2.0",
@@ -3327,7 +3328,7 @@ version = "0.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fa95a34622365fa5bbf40b20b75dba8dfa8c94c734aea8ac9a5ca38af14316f1"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"core-foundation 0.10.0",
"core-graphics-types 0.2.0",
"foreign-types 0.5.0",
@@ -3351,7 +3352,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"core-foundation 0.10.0",
"libc",
]
@@ -3423,7 +3424,7 @@ version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e418dd4f5128c3e93eab12246391c54a20c496811131f85754dc8152ee207892"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"fontdb 0.16.2",
"log",
"rangemap",
@@ -5076,7 +5077,7 @@ name = "font-kit"
version = "0.14.1"
source = "git+https://github.com/zed-industries/font-kit?rev=40391b7#40391b7c0041d8a8572af2afa3de32ae088f0120"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"byteorder",
"core-foundation 0.9.4",
"core-graphics 0.23.2",
@@ -5276,7 +5277,7 @@ checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c"
name = "fsevent"
version = "0.1.0"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"core-foundation 0.9.4",
"fsevent-sys 3.1.0",
"parking_lot",
@@ -5604,7 +5605,7 @@ version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5220b8ba44c68a9a7f7a7659e864dd73692e417ef0211bea133c7b74e031eeb9"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"libc",
"libgit2-sys",
"log",
@@ -5770,7 +5771,7 @@ version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"gpu-alloc-types",
]
@@ -5791,7 +5792,7 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
]
[[package]]
@@ -6103,7 +6104,7 @@ version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd54745cfacb7b97dee45e8fdb91814b62bccddb481debb7de0f9ee6b7bf5b43"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"byteorder",
"heed-traits",
"heed-types",
@@ -6663,9 +6664,9 @@ dependencies = [
[[package]]
name = "image"
version = "0.25.6"
version = "0.25.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "db35664ce6b9810857a38a906215e75a9c879f0696556a39f59c62829710251a"
checksum = "cd6f44aed642f18953a158afeb30206f4d50da59fbc66ecb53c66488de73563b"
dependencies = [
"bytemuck",
"byteorder-lite",
@@ -6840,7 +6841,7 @@ version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"inotify-sys",
"libc",
]
@@ -7581,7 +7582,7 @@ version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"libc",
"redox_syscall 0.5.8",
]
@@ -8220,7 +8221,7 @@ version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"block",
"core-graphics-types 0.1.3",
"foreign-types 0.5.0",
@@ -8385,7 +8386,7 @@ checksum = "364f94bc34f61332abebe8cad6f6cd82a5b65cff22c828d05d0968911462ca4f"
dependencies = [
"arrayvec",
"bit-set 0.8.0",
"bitflags 2.9.0",
"bitflags 2.8.0",
"cfg_aliases 0.1.1",
"codespan-reporting",
"hexf-parse",
@@ -8454,7 +8455,7 @@ version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2076a31b7010b17a38c01907c45b945e8f11495ee4dd588309718901b1f7a5b7"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"jni-sys",
"log",
"ndk-sys",
@@ -8489,7 +8490,7 @@ version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"cfg-if",
"cfg_aliases 0.2.1",
"libc",
@@ -8573,7 +8574,7 @@ version = "8.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"filetime",
"fsevent-sys 4.1.0",
"inotify",
@@ -8591,7 +8592,7 @@ name = "notify"
version = "8.0.0"
source = "git+https://github.com/zed-industries/notify.git?rev=bbb9ea5ae52b253e095737847e367c30653a2e96#bbb9ea5ae52b253e095737847e367c30653a2e96"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"filetime",
"fsevent-sys 4.1.0",
"inotify",
@@ -8867,7 +8868,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"block2",
"libc",
"objc2",
@@ -8883,7 +8884,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"block2",
"objc2",
"objc2-core-location",
@@ -8907,7 +8908,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"block2",
"objc2",
"objc2-foundation",
@@ -8949,7 +8950,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"block2",
"libc",
"objc2",
@@ -8973,7 +8974,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"block2",
"objc2",
"objc2-foundation",
@@ -8985,7 +8986,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"block2",
"objc2",
"objc2-foundation",
@@ -9008,7 +9009,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"block2",
"objc2",
"objc2-cloud-kit",
@@ -9040,7 +9041,7 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"block2",
"objc2",
"objc2-core-location",
@@ -9183,7 +9184,7 @@ version = "0.10.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61cfb4e166a8bb8c9b55c500bc2308550148ece889be90f609377e58140f42c6"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"cfg-if",
"foreign-types 0.3.2",
"libc",
@@ -10712,7 +10713,7 @@ checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4"
dependencies = [
"bytes 1.10.1",
"heck 0.4.1",
"itertools 0.10.5",
"itertools 0.12.1",
"log",
"multimap 0.10.0",
"once_cell",
@@ -10745,7 +10746,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1"
dependencies = [
"anyhow",
"itertools 0.10.5",
"itertools 0.12.1",
"proc-macro2",
"quote",
"syn 2.0.100",
@@ -10822,7 +10823,7 @@ version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"memchr",
"pulldown-cmark-escape",
"unicase",
@@ -10834,7 +10835,7 @@ version = "0.12.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f86ba2052aebccc42cbbb3ed234b8b13ce76f75c3551a303cb2bcffcff12bb14"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"memchr",
"unicase",
]
@@ -11215,7 +11216,7 @@ version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
]
[[package]]
@@ -11858,7 +11859,7 @@ version = "0.38.42"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f93dc38ecbab2eb790ff964bb77fa94faf256fd3e73285fd7ba0903b76bedb85"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"errno 0.3.10",
"itoa",
"libc",
@@ -12018,7 +12019,7 @@ version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cfb9cf8877777222e4a3bc7eb247e398b56baba500c38c1c46842431adc8b55c"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"bytemuck",
"libm",
"smallvec",
@@ -12035,7 +12036,7 @@ version = "0.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fd3c7c96f8a08ee34eff8857b11b49b07d71d1c3f4e88f8a88d4c9e9f90b1702"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"bytemuck",
"core_maths",
"log",
@@ -12258,7 +12259,7 @@ version = "0.1.0"
dependencies = [
"any_vec",
"anyhow",
"bitflags 2.9.0",
"bitflags 2.8.0",
"client",
"collections",
"editor",
@@ -12300,7 +12301,7 @@ version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"core-foundation 0.9.4",
"core-foundation-sys",
"libc",
@@ -12313,7 +12314,7 @@ version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1415a607e92bec364ea2cf9264646dcce0f91e6d65281bd6f2819cca3bf39c8"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"core-foundation 0.10.0",
"core-foundation-sys",
"libc",
@@ -12913,7 +12914,7 @@ version = "0.3.0+sdk-1.3.268.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
]
[[package]]
@@ -13080,7 +13081,7 @@ dependencies = [
"atoi",
"base64 0.22.1",
"bigdecimal",
"bitflags 2.9.0",
"bitflags 2.8.0",
"byteorder",
"bytes 1.10.1",
"chrono",
@@ -13127,7 +13128,7 @@ dependencies = [
"atoi",
"base64 0.22.1",
"bigdecimal",
"bitflags 2.9.0",
"bitflags 2.8.0",
"byteorder",
"chrono",
"crc",
@@ -13589,7 +13590,7 @@ version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"core-foundation 0.9.4",
"system-configuration-sys 0.6.0",
]
@@ -13633,7 +13634,7 @@ version = "0.27.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc4592f674ce18521c2a81483873a49596655b179f71c5e05d10c1fe66c78745"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"cap-fs-ext",
"cap-std",
"fd-lock",
@@ -14453,7 +14454,7 @@ version = "0.4.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"bytes 1.10.1",
"futures-core",
"futures-util",
@@ -15366,7 +15367,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5924018406ce0063cd67f8e008104968b74b563ee1b85dde3ed1f7cb87d3dbd"
dependencies = [
"arrayvec",
"bitflags 2.9.0",
"bitflags 2.8.0",
"cursor-icon",
"log",
"memchr",
@@ -15590,7 +15591,7 @@ version = "0.201.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "84e5df6dba6c0d7fafc63a450f1738451ed7a0b52295d83e868218fa286bf708"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"indexmap",
"semver",
]
@@ -15601,7 +15602,7 @@ version = "0.221.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d06bfa36ab3ac2be0dee563380147a5b81ba10dd8885d7fbbc9eb574be67d185"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"hashbrown 0.15.2",
"indexmap",
"semver",
@@ -15627,7 +15628,7 @@ checksum = "11976a250672556d1c4c04c6d5d7656ac9192ac9edc42a4587d6c21460010e69"
dependencies = [
"anyhow",
"async-trait",
"bitflags 2.9.0",
"bitflags 2.8.0",
"bumpalo",
"cc",
"cfg-if",
@@ -15833,7 +15834,7 @@ checksum = "8d1be69bfcab1bdac74daa7a1f9695ab992b9c8e21b9b061e7d66434097e0ca4"
dependencies = [
"anyhow",
"async-trait",
"bitflags 2.9.0",
"bitflags 2.8.0",
"bytes 1.10.1",
"cap-fs-ext",
"cap-net-ext",
@@ -15914,7 +15915,7 @@ version = "0.31.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2120de3d33638aaef5b9f4472bff75f07c56379cf76ea320bd3a3d65ecaf73f"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"rustix",
"wayland-backend",
"wayland-scanner",
@@ -15937,7 +15938,7 @@ version = "0.31.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f81f365b8b4a97f422ac0e8737c438024b5951734506b0e1d775c73030561f4"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"wayland-backend",
"wayland-client",
"wayland-scanner",
@@ -15949,7 +15950,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23803551115ff9ea9bce586860c5c5a971e360825a0309264102a9495a5ff479"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"wayland-backend",
"wayland-client",
"wayland-protocols",
@@ -16116,7 +16117,7 @@ checksum = "4b9af35bc9629c52c261465320a9a07959164928b4241980ba1cf923b9e6751d"
dependencies = [
"anyhow",
"async-trait",
"bitflags 2.9.0",
"bitflags 2.8.0",
"thiserror 1.0.69",
"tracing",
"wasmtime",
@@ -16731,7 +16732,7 @@ version = "0.36.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"windows-sys 0.52.0",
]
@@ -16750,7 +16751,7 @@ version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "288f992ea30e6b5c531b52cdd5f3be81c148554b09ea416f058d16556ba92c27"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
"wit-bindgen-rt 0.22.0",
"wit-bindgen-rust-macro",
]
@@ -16777,7 +16778,7 @@ version = "0.33.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
]
[[package]]
@@ -16815,7 +16816,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "421c0c848a0660a8c22e2fd217929a0191f14476b68962afd2af89fd22e39825"
dependencies = [
"anyhow",
"bitflags 2.9.0",
"bitflags 2.8.0",
"indexmap",
"log",
"serde",
@@ -16834,7 +16835,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66c55ca8772d2b270e28066caed50ce4e53a28c3ac10e01efbd90e5be31e448b"
dependencies = [
"anyhow",
"bitflags 2.9.0",
"bitflags 2.8.0",
"indexmap",
"log",
"serde",
@@ -17077,7 +17078,7 @@ name = "xim-parser"
version = "0.2.1"
source = "git+https://github.com/XDeme1/xim-rs?rev=d50d461764c2213655cd9cf65a0ea94c70d3c4fd#d50d461764c2213655cd9cf65a0ea94c70d3c4fd"
dependencies = [
"bitflags 2.9.0",
"bitflags 2.8.0",
]
[[package]]

View File

@@ -25,6 +25,7 @@ assistant_settings.workspace = true
assistant_slash_command.workspace = true
assistant_tool.workspace = true
async-watch.workspace = true
buffer_diff.workspace = true
chrono.workspace = true
client.workspace = true
clock.workspace = true
@@ -85,6 +86,7 @@ workspace.workspace = true
zed_actions.workspace = true
[dev-dependencies]
buffer_diff = { workspace = true, features = ["test-support"] }
editor = { workspace = true, features = ["test-support"] }
gpui = { workspace = true, "features" = ["test-support"] }
indoc.workspace = true

View File

@@ -521,6 +521,10 @@ impl ActiveThread {
}
}
ThreadEvent::CheckpointChanged => cx.notify(),
ThreadEvent::DiffChanged => {
// todo!("update list of changed files")
cx.notify();
}
}
}

View File

@@ -15,6 +15,7 @@ mod profile_selector;
mod terminal_codegen;
mod terminal_inline_assistant;
mod thread;
mod thread_diff;
mod thread_history;
mod thread_store;
mod tool_use;
@@ -36,6 +37,7 @@ use crate::assistant_configuration::{AddContextServerModal, ManageProfilesModal}
pub use crate::assistant_panel::{AssistantPanel, ConcreteAssistantPanelDelegate};
pub use crate::inline_assistant::InlineAssistant;
pub use crate::thread::{Message, RequestKind, Thread, ThreadEvent};
pub(crate) use crate::thread_diff::*;
pub use crate::thread_store::ThreadStore;
actions!(
@@ -60,7 +62,8 @@ actions!(
FocusRight,
RemoveFocusedContext,
AcceptSuggestedContext,
OpenActiveThreadAsMarkdown
OpenActiveThreadAsMarkdown,
ShowThreadDiff
]
);

View File

@@ -29,7 +29,7 @@ use crate::context_strip::{ContextStrip, ContextStripEvent, SuggestContextKind};
use crate::profile_selector::ProfileSelector;
use crate::thread::{RequestKind, Thread};
use crate::thread_store::ThreadStore;
use crate::{Chat, ChatMode, RemoveAllContext, ThreadEvent, ToggleContextPicker};
use crate::{Chat, ChatMode, RemoveAllContext, ShowThreadDiff, ThreadEvent, ToggleContextPicker};
pub struct MessageEditor {
thread: Entity<Thread>,
@@ -152,6 +152,32 @@ impl MessageEditor {
) {
self.context_picker_menu_handle.toggle(window, cx);
}
fn show_thread_diff(
&mut self,
_: &ShowThreadDiff,
window: &mut Window,
cx: &mut Context<Self>,
) {
let Some(workspace) = self.workspace.upgrade() else {
return;
};
let diff_source = Arc::new(self.thread.read(cx).diff_source(cx));
let project_diff = cx.new(|cx| {
git_ui::project_diff::ProjectDiff::new(
diff_source,
self.project.clone(),
workspace.clone(),
window,
cx,
)
});
workspace.update(cx, |workspace, cx| {
workspace.add_item_to_active_pane(Box::new(project_diff), None, true, window, cx)
});
}
pub fn remove_all_context(
&mut self,
_: &RemoveAllContext,
@@ -565,6 +591,7 @@ impl Render for MessageEditor {
this.model_selector
.update(cx, |model_selector, cx| model_selector.toggle(window, cx));
}))
.on_action(cx.listener(Self::show_thread_diff))
.on_action(cx.listener(Self::toggle_context_picker))
.on_action(cx.listener(Self::remove_all_context))
.on_action(cx.listener(Self::move_up))

View File

@@ -34,6 +34,7 @@ use crate::thread_store::{
SerializedToolUse,
};
use crate::tool_use::{PendingToolUse, ToolUse, ToolUseState};
use crate::{ChangeAuthor, ThreadDiff, ThreadDiffSource};
#[derive(Debug, Clone, Copy)]
pub enum RequestKind {
@@ -181,6 +182,7 @@ pub struct Thread {
completion_count: usize,
pending_completions: Vec<PendingCompletion>,
project: Entity<Project>,
git_store: Entity<GitStore>,
prompt_builder: Arc<PromptBuilder>,
tools: Arc<ToolWorkingSet>,
tool_use: ToolUseState,
@@ -190,6 +192,7 @@ pub struct Thread {
initial_project_snapshot: Shared<Task<Option<Arc<ProjectSnapshot>>>>,
cumulative_token_usage: TokenUsage,
feedback: Option<ThreadFeedback>,
diff: Entity<ThreadDiff>,
}
impl Thread {
@@ -213,6 +216,7 @@ impl Thread {
completion_count: 0,
pending_completions: Vec::new(),
project: project.clone(),
git_store: project.read(cx).git_store().clone(),
prompt_builder,
tools: tools.clone(),
last_restore_checkpoint: None,
@@ -220,13 +224,14 @@ impl Thread {
tool_use: ToolUseState::new(tools.clone()),
action_log: cx.new(|_| ActionLog::new()),
initial_project_snapshot: {
let project_snapshot = Self::project_snapshot(project, cx);
let project_snapshot = Self::project_snapshot(project.clone(), cx);
cx.foreground_executor()
.spawn(async move { Some(project_snapshot.await) })
.shared()
},
cumulative_token_usage: TokenUsage::default(),
feedback: None,
diff: cx.new(|cx| ThreadDiff::new(project.clone(), cx)),
}
}
@@ -280,6 +285,8 @@ impl Thread {
pending_completions: Vec::new(),
last_restore_checkpoint: None,
pending_checkpoint: None,
diff: cx.new(|cx| ThreadDiff::new(project.clone(), cx)),
git_store: project.read(cx).git_store().clone(),
project,
prompt_builder,
tools,
@@ -356,6 +363,15 @@ impl Thread {
!self.tool_use.pending_tool_uses().is_empty()
}
pub fn diff_source(&self, cx: &App) -> ThreadDiffSource {
let project = self.project.read(cx);
ThreadDiffSource::new(
self.diff.clone(),
project.git_store().clone(),
project.languages().clone(),
)
}
pub fn checkpoint_for_message(&self, id: MessageId) -> Option<ThreadCheckpoint> {
self.checkpoints_by_message.get(&id).cloned()
}
@@ -1231,17 +1247,37 @@ impl Thread {
tool: Arc<dyn Tool>,
cx: &mut Context<Thread>,
) -> Task<()> {
let run_tool = tool.run(
input,
messages,
self.project.clone(),
self.action_log.clone(),
cx,
);
let diff = self.diff.clone();
let git_store = self.git_store.clone();
let checkpoint = git_store.read(cx).checkpoint(cx);
let messages = messages.to_vec();
let project = self.project.clone();
let action_log = self.action_log.clone();
cx.spawn({
async move |thread: WeakEntity<Thread>, cx| {
let output = run_tool.await;
if let Ok(checkpoint) = checkpoint.await {
diff.update(cx, |diff, cx| {
diff.compute_changes(ChangeAuthor::User, checkpoint)
})
.ok();
}
let Ok(output) =
cx.update(|cx| tool.run(input, &messages, project, action_log, cx))
else {
return;
};
let output = output.await;
if let Ok(checkpoint) = git_store.read_with(cx, |git, cx| git.checkpoint(cx)) {
if let Ok(checkpoint) = checkpoint.await {
diff.update(cx, |diff, cx| {
diff.compute_changes(ChangeAuthor::Agent, checkpoint)
})
.ok();
}
}
thread
.update(cx, |thread, cx| {
@@ -1562,6 +1598,7 @@ pub enum ThreadEvent {
canceled: bool,
},
CheckpointChanged,
DiffChanged,
ToolConfirmationNeeded,
}

View File

@@ -0,0 +1,219 @@
use anyhow::{Context as _, Result};
use buffer_diff::BufferDiff;
use collections::HashMap;
use futures::{channel::mpsc, future::Shared, FutureExt, StreamExt};
use gpui::{prelude::*, App, Entity, Subscription, Task};
use language::{Buffer, LanguageRegistry};
use project::{
git_store::{GitStore, GitStoreCheckpoint, GitStoreIndex, GitStoreStatus},
Project,
};
use std::sync::Arc;
use util::TryFutureExt;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ChangeAuthor {
User,
Agent,
}
pub struct ThreadDiff {
base: Shared<Task<Option<GitStoreIndex>>>,
diffs_by_buffer: HashMap<Entity<Buffer>, Entity<BufferDiff>>,
status: GitStoreStatus,
project: Entity<Project>,
git_store: Entity<GitStore>,
checkpoints_tx: mpsc::UnboundedSender<(ChangeAuthor, GitStoreCheckpoint)>,
update_status_tx: async_watch::Sender<()>,
_subscription: Subscription,
_maintain_status: Task<Result<()>>,
_maintain_diff: Task<Result<()>>,
}
impl ThreadDiff {
pub fn new(project: Entity<Project>, cx: &mut Context<Self>) -> Self {
let git_store = project.read(cx).git_store().clone();
let (checkpoints_tx, mut checkpoints_rx) = mpsc::unbounded();
let (update_status_tx, mut update_status_rx) = async_watch::channel(());
let checkpoint = git_store.read(cx).checkpoint(cx);
let base = cx
.background_spawn(
project
.read(cx)
.git_store()
.read(cx)
.create_index(cx)
.log_err(),
)
.shared();
Self {
base: base.clone(),
status: GitStoreStatus::default(),
diffs_by_buffer: HashMap::default(),
git_store: git_store.clone(),
project,
checkpoints_tx,
update_status_tx,
_subscription: cx.subscribe(&git_store, |this, _git_store, event, _cx| {
if let project::git_store::GitEvent::FileSystemUpdated = event {
this.update_status_tx.send(()).ok();
}
}),
_maintain_status: cx.spawn({
let git_store = git_store.clone();
let base = base.clone();
async move |this, cx| {
let base = base.await.context("failed to create base")?;
while let Ok(()) = update_status_rx.recv().await {
let status = git_store
.read_with(cx, |store, cx| store.status(Some(base.clone()), cx))?
.await
.unwrap_or_default();
this.update(cx, |this, cx| this.set_status(status, cx))?;
}
Ok(())
}
}),
_maintain_diff: cx.spawn(async move |this, cx| {
let mut last_checkpoint = checkpoint.await.ok();
let base = base.await.context("failed to create base")?;
while let Some((author, checkpoint)) = checkpoints_rx.next().await {
if let Some(last_checkpoint) = last_checkpoint {
if author == ChangeAuthor::User {
let diff = git_store
.read_with(cx, |store, cx| {
store.diff_checkpoints(last_checkpoint, checkpoint.clone(), cx)
})?
.await;
if let Ok(diff) = diff {
_ = git_store
.read_with(cx, |store, cx| {
store.apply_diff(base.clone(), diff, cx)
})?
.await;
}
}
this.update(cx, |this, _cx| this.update_status_tx.send(()).ok())?;
}
last_checkpoint = Some(checkpoint);
}
Ok(())
}),
}
}
pub fn compute_changes(&mut self, author: ChangeAuthor, checkpoint: GitStoreCheckpoint) {
_ = self.checkpoints_tx.unbounded_send((author, checkpoint));
}
fn set_status(&mut self, status: GitStoreStatus, cx: &mut Context<Self>) {
self.status = status;
cx.notify();
}
}
pub struct ThreadDiffSource {
thread_diff: Entity<ThreadDiff>,
git_store: Entity<GitStore>,
language_registry: Arc<LanguageRegistry>,
}
impl ThreadDiffSource {
pub fn new(
thread_diff: Entity<ThreadDiff>,
git_store: Entity<GitStore>,
language_registry: Arc<LanguageRegistry>,
) -> Self {
Self {
thread_diff,
git_store,
language_registry,
}
}
}
impl git_ui::project_diff::DiffSource for ThreadDiffSource {
fn observe(&self, cx: &mut App, mut f: Box<dyn FnMut(&mut App) + Send>) -> Subscription {
cx.observe(&self.thread_diff, move |_, cx| f(cx))
}
fn status(&self, cx: &App) -> Vec<git_ui::project_diff::StatusEntry> {
let mut results = Vec::new();
for (repo, repo_path, status) in self
.thread_diff
.read(cx)
.status
.entries(&self.git_store, cx)
{
let Some(project_path) = repo.read(cx).repo_path_to_project_path(repo_path, cx) else {
continue;
};
let status = match *status {
git::status::FileStatus::Tracked(mut tracked_status) => {
if tracked_status.worktree_status == git::status::StatusCode::Unmodified {
continue;
} else {
tracked_status.index_status = git::status::StatusCode::Unmodified;
git::status::FileStatus::Tracked(tracked_status)
}
}
status @ _ => status,
};
results.push(git_ui::project_diff::StatusEntry {
project_path,
status,
has_conflict: false,
});
}
results
}
fn open_uncommitted_diff(
&self,
buffer: Entity<Buffer>,
cx: &mut App,
) -> Task<Result<Entity<BufferDiff>>> {
let base = self.thread_diff.read(cx).base.clone();
let git_store = self.git_store.clone();
let language_registry = self.language_registry.clone();
let thread_diff = self.thread_diff.clone();
cx.spawn(async move |cx| {
let base = base.await.context("failed to load diff base")?;
let base_text = git_store
.read_with(cx, |git, cx| git.load_index_text(Some(base), &buffer, cx))?
.await;
let snapshot = buffer.read_with(cx, |buffer, _cx| buffer.snapshot())?;
let diff = thread_diff.update(cx, |thread_diff, cx| {
thread_diff
.diffs_by_buffer
.entry(buffer.clone())
.or_insert_with(|| cx.new(|cx| BufferDiff::new(&snapshot, cx)))
.clone()
})?;
let base_text = Arc::new(base_text.unwrap_or_default());
let diff_snapshot = BufferDiff::update_diff(
diff.clone(),
snapshot.text.clone(),
Some(base_text),
true,
false,
snapshot.language().cloned(),
Some(language_registry),
cx,
)
.await?;
diff.update(cx, |diff, cx| {
diff.set_snapshot(&snapshot, diff_snapshot, false, None, cx);
})?;
Ok(diff)
})
}
}

View File

@@ -1308,7 +1308,7 @@ impl GitRepository for RealGitRepository {
.spawn(async move {
let working_directory = working_directory?;
let git = GitBinary::new(git_binary_path, working_directory, executor);
git.run(&[
git.run_raw(&[
"diff",
"--find-renames",
"--patch",
@@ -1463,7 +1463,7 @@ impl GitBinary {
S: AsRef<OsStr>,
{
let mut stdout = self.run_raw(args).await?;
if stdout.chars().last() == Some('\n') {
if stdout.ends_with('\n') {
stdout.pop();
}
Ok(stdout)

View File

@@ -26,7 +26,11 @@ use project::{
git_store::{GitEvent, GitStore},
Project, ProjectPath,
};
use std::any::{Any, TypeId};
use std::{
any::{Any, TypeId},
path::Path,
sync::Arc,
};
use theme::ActiveTheme;
use ui::{prelude::*, vertical_divider, KeyBinding, Tooltip};
use util::ResultExt as _;
@@ -39,7 +43,67 @@ use workspace::{
actions!(git, [Diff, Add]);
#[derive(Debug)]
pub struct StatusEntry {
pub project_path: ProjectPath,
pub status: FileStatus,
pub has_conflict: bool,
}
pub trait DiffSource {
fn observe(&self, cx: &mut App, f: Box<dyn FnMut(&mut App) + Send>) -> Subscription;
fn status(&self, cx: &App) -> Vec<StatusEntry>;
fn open_uncommitted_diff(
&self,
buffer: Entity<Buffer>,
cx: &mut App,
) -> Task<Result<Entity<BufferDiff>>>;
}
pub struct ProjectDiffSource(Entity<Project>);
impl DiffSource for ProjectDiffSource {
fn observe(&self, cx: &mut App, mut f: Box<dyn FnMut(&mut App) + Send>) -> Subscription {
let git_store = self.0.read(cx).git_store().clone();
cx.subscribe(&git_store, move |_git_store, event, cx| match event {
GitEvent::ActiveRepositoryChanged
| GitEvent::FileSystemUpdated
| GitEvent::GitStateUpdated => f(cx),
_ => {}
})
}
fn status(&self, cx: &App) -> Vec<StatusEntry> {
let mut result = Vec::new();
if let Some(git_repo) = self.0.read(cx).git_store().read(cx).active_repository() {
let git_repo = git_repo.read(cx);
for entry in git_repo.cached_status() {
if let Some(project_path) = git_repo.repo_path_to_project_path(&entry.repo_path, cx)
{
let has_conflict = git_repo.has_conflict(&entry.repo_path);
result.push(StatusEntry {
project_path,
status: entry.status,
has_conflict,
});
}
}
}
result
}
fn open_uncommitted_diff(
&self,
buffer: Entity<Buffer>,
cx: &mut App,
) -> Task<Result<Entity<BufferDiff>>> {
self.0
.update(cx, |project, cx| project.open_uncommitted_diff(buffer, cx))
}
}
pub struct ProjectDiff {
source: Arc<dyn DiffSource>,
project: Entity<Project>,
multibuffer: Entity<MultiBuffer>,
editor: Entity<Editor>,
@@ -102,8 +166,16 @@ impl ProjectDiff {
existing
} else {
let workspace_handle = cx.entity();
let project_diff =
cx.new(|cx| Self::new(workspace.project().clone(), workspace_handle, window, cx));
let source = Arc::new(ProjectDiffSource(workspace.project().clone()));
let project_diff = cx.new(|cx| {
Self::new(
source,
workspace.project().clone(),
workspace_handle,
window,
cx,
)
});
workspace.add_item_to_active_pane(
Box::new(project_diff.clone()),
None,
@@ -126,7 +198,8 @@ impl ProjectDiff {
})
}
fn new(
pub fn new(
source: Arc<dyn DiffSource>,
project: Entity<Project>,
workspace: Entity<Workspace>,
window: &mut Window,
@@ -149,17 +222,16 @@ impl ProjectDiff {
.detach();
let git_store = project.read(cx).git_store().clone();
let git_store_subscription = cx.subscribe_in(
&git_store,
window,
move |this, _git_store, event, _window, _cx| match event {
GitEvent::ActiveRepositoryChanged
| GitEvent::FileSystemUpdated
| GitEvent::GitStateUpdated => {
*this.update_needed.borrow_mut() = ();
}
_ => {}
},
let weak_this = cx.weak_entity();
let diff_source_subscription = source.observe(
cx,
Box::new(move |cx| {
weak_this
.update(cx, |this, _| {
*this.update_needed.borrow_mut() = ();
})
.ok();
}),
);
let (mut send, recv) = postage::watch::channel::<()>();
@@ -171,6 +243,7 @@ impl ProjectDiff {
*send.borrow_mut() = ();
Self {
source,
project,
git_store: git_store.clone(),
workspace: workspace.downgrade(),
@@ -181,7 +254,7 @@ impl ProjectDiff {
update_needed: send,
current_branch: None,
_task: worker,
_subscription: git_store_subscription,
_subscription: diff_source_subscription,
}
}
@@ -328,56 +401,53 @@ impl ProjectDiff {
}
fn load_buffers(&mut self, cx: &mut Context<Self>) -> Vec<Task<Result<DiffBuffer>>> {
let Some(repo) = self.git_store.read(cx).active_repository() else {
self.multibuffer.update(cx, |multibuffer, cx| {
multibuffer.clear(cx);
});
return vec![];
};
let mut previous_paths = self.multibuffer.read(cx).paths().collect::<HashSet<_>>();
let mut result = vec![];
repo.update(cx, |repo, cx| {
for entry in repo.cached_status() {
if !entry.status.has_changes() {
continue;
}
let Some(project_path) = repo.repo_path_to_project_path(&entry.repo_path, cx)
else {
continue;
};
let namespace = if repo.has_conflict(&entry.repo_path) {
CONFLICT_NAMESPACE
} else if entry.status.is_created() {
NEW_NAMESPACE
} else {
TRACKED_NAMESPACE
};
let path_key = PathKey::namespaced(namespace, entry.repo_path.0.clone());
previous_paths.remove(&path_key);
let load_buffer = self
.project
.update(cx, |project, cx| project.open_buffer(project_path, cx));
let project = self.project.clone();
result.push(cx.spawn(async move |_, cx| {
let buffer = load_buffer.await?;
let changes = project
.update(cx, |project, cx| {
project.open_uncommitted_diff(buffer.clone(), cx)
})?
.await?;
Ok(DiffBuffer {
path_key,
buffer,
diff: changes,
file_status: entry.status,
})
}));
for entry in self.source.status(cx) {
if !entry.status.has_changes() {
continue;
}
});
let Some(worktree) = self
.project
.read(cx)
.worktree_for_id(entry.project_path.worktree_id, cx)
else {
continue;
};
let full_path =
Arc::from(Path::new(worktree.read(cx).root_name()).join(&entry.project_path.path));
let namespace = if entry.has_conflict {
CONFLICT_NAMESPACE
} else if entry.status.is_created() {
NEW_NAMESPACE
} else {
TRACKED_NAMESPACE
};
let path_key = PathKey::namespaced(namespace, full_path);
previous_paths.remove(&path_key);
let load_buffer = self.project.update(cx, |project, cx| {
project.open_buffer(entry.project_path, cx)
});
let source = self.source.clone();
result.push(cx.spawn(async move |_, cx| {
let buffer = load_buffer.await?;
let changes = cx
.update(|cx| source.open_uncommitted_diff(buffer.clone(), cx))?
.await?;
Ok(DiffBuffer {
path_key,
buffer,
diff: changes,
file_status: entry.status,
})
}));
}
self.multibuffer.update(cx, |multibuffer, cx| {
for path in previous_paths {
multibuffer.remove_excerpts_for_path(path, cx);
@@ -586,7 +656,15 @@ impl Item for ProjectDiff {
Self: Sized,
{
let workspace = self.workspace.upgrade()?;
Some(cx.new(|cx| ProjectDiff::new(self.project.clone(), workspace, window, cx)))
Some(cx.new(|cx| {
ProjectDiff::new(
self.source.clone(),
self.project.clone(),
workspace,
window,
cx,
)
}))
}
fn is_dirty(&self, cx: &App) -> bool {
@@ -744,7 +822,7 @@ impl SerializableItem for ProjectDiff {
}
fn deserialize(
_project: Entity<Project>,
project: Entity<Project>,
workspace: WeakEntity<Workspace>,
_workspace_id: workspace::WorkspaceId,
_item_id: workspace::ItemId,
@@ -754,7 +832,16 @@ impl SerializableItem for ProjectDiff {
window.spawn(cx, async move |cx| {
workspace.update_in(cx, |workspace, window, cx| {
let workspace_handle = cx.entity();
cx.new(|cx| Self::new(workspace.project().clone(), workspace_handle, window, cx))
let diff = Arc::new(ProjectDiffSource(project));
cx.new(|cx| {
Self::new(
diff,
workspace.project().clone(),
workspace_handle,
window,
cx,
)
})
})
})
}
@@ -1338,8 +1425,9 @@ mod tests {
let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
let (workspace, cx) =
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
let source = Arc::new(ProjectDiffSource(project.clone()));
let diff = cx.new_window_entity(|window, cx| {
ProjectDiff::new(project.clone(), workspace, window, cx)
ProjectDiff::new(source, project.clone(), workspace, window, cx)
});
cx.run_until_parked();
@@ -1392,8 +1480,9 @@ mod tests {
let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
let (workspace, cx) =
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
let source = Arc::new(ProjectDiffSource(project.clone()));
let diff = cx.new_window_entity(|window, cx| {
ProjectDiff::new(project.clone(), workspace, window, cx)
ProjectDiff::new(source, project.clone(), workspace, window, cx)
});
cx.run_until_parked();
@@ -1465,6 +1554,7 @@ mod tests {
let project = Project::test(fs.clone(), [path!("/project").as_ref()], cx).await;
let (workspace, cx) =
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
let source = Arc::new(ProjectDiffSource(project.clone()));
let buffer = project
.update(cx, |project, cx| {
project.open_local_buffer(path!("/project/foo"), cx)
@@ -1475,7 +1565,7 @@ mod tests {
Editor::for_buffer(buffer, Some(project.clone()), window, cx)
});
let diff = cx.new_window_entity(|window, cx| {
ProjectDiff::new(project.clone(), workspace, window, cx)
ProjectDiff::new(source, project.clone(), workspace, window, cx)
});
cx.run_until_parked();

View File

@@ -158,10 +158,45 @@ pub struct GitStoreIndex {
#[derive(Default)]
pub struct GitStoreStatus {
#[allow(dead_code)]
statuses_by_work_dir_abs_path: HashMap<PathBuf, GitStatus>,
}
impl GitStoreStatus {
pub fn entries<'a>(
&'a self,
git_store: &Entity<GitStore>,
cx: &App,
) -> impl 'a + Iterator<Item = (Entity<Repository>, &'a RepoPath, &'a FileStatus)> {
let repositories_by_work_dir_abs_path = git_store
.read(cx)
.repositories
.values()
.map(|repo| {
(
repo.read(cx)
.repository_entry
.work_directory_abs_path
.clone(),
repo.clone(),
)
})
.collect::<HashMap<_, _>>();
self.statuses_by_work_dir_abs_path
.iter()
.flat_map(move |(work_dir_abs_path, status)| {
status
.entries
.iter()
.map(move |(repo_path, status)| (work_dir_abs_path, repo_path, status))
})
.filter_map(move |(work_dir_abs_path, repo_path, status)| {
let repository = repositories_by_work_dir_abs_path.get(work_dir_abs_path)?;
Some((repository.clone(), repo_path, status))
})
}
}
pub struct Repository {
pub repository_entry: RepositoryEntry,
pub merge_message: Option<String>,
@@ -790,7 +825,11 @@ impl GitStore {
.diff_checkpoints(base_checkpoint, target_checkpoint);
tasks.push(async move {
let diff = diff.await??;
anyhow::Ok((work_dir_abs_path, diff))
if diff.is_empty() {
anyhow::Ok(None)
} else {
anyhow::Ok(Some((work_dir_abs_path, diff)))
}
});
}
}
@@ -799,7 +838,10 @@ impl GitStore {
cx.background_spawn(async move {
let diffs_by_path = future::try_join_all(tasks).await?;
Ok(GitStoreDiff {
diffs_by_work_dir_abs_path: diffs_by_path.into_iter().collect(),
diffs_by_work_dir_abs_path: diffs_by_path
.into_iter()
.filter_map(|diff| diff)
.collect(),
})
})
}