add issues and prs button

This commit is contained in:
2026-08-17 09:13:04 +07:00
parent 2d281dfbbb
commit 9f484ea98d
4 changed files with 275 additions and 319 deletions
Generated
+73 -53
View File
@@ -1244,7 +1244,7 @@ dependencies = [
[[package]] [[package]]
name = "collections" name = "collections"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"gpui_util", "gpui_util",
"indexmap", "indexmap",
@@ -1701,7 +1701,7 @@ dependencies = [
[[package]] [[package]]
name = "derive_refineable" name = "derive_refineable"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -2094,9 +2094,9 @@ dependencies = [
[[package]] [[package]]
name = "find-msvc-tools" name = "find-msvc-tools"
version = "0.1.10" version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26b73573e6edcd2af0cdf47bd6cb58f0b3839491263c314eaad1ccf24430e1de" checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890"
[[package]] [[package]]
name = "fixedbitset" name = "fixedbitset"
@@ -3436,7 +3436,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui" name = "gpui"
version = "0.2.2" version = "0.2.2"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"accesskit", "accesskit",
"anyhow", "anyhow",
@@ -3520,7 +3520,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui-base" name = "gpui-base"
version = "0.5.2" version = "0.5.2"
source = "git+https://github.com/longbridge/gpui-component#b83e4a3a950cfe28a30e4b5a73ad0dd06a821593" source = "git+https://github.com/longbridge/gpui-component#da4f93696dc2b2b4d91bcc42412b9053a3d24de8"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"anyhow", "anyhow",
@@ -3550,7 +3550,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui-component" name = "gpui-component"
version = "0.5.2" version = "0.5.2"
source = "git+https://github.com/longbridge/gpui-component#b83e4a3a950cfe28a30e4b5a73ad0dd06a821593" source = "git+https://github.com/longbridge/gpui-component#da4f93696dc2b2b4d91bcc42412b9053a3d24de8"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
@@ -3630,7 +3630,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui-component-assets" name = "gpui-component-assets"
version = "0.5.1" version = "0.5.1"
source = "git+https://github.com/longbridge/gpui-component#b83e4a3a950cfe28a30e4b5a73ad0dd06a821593" source = "git+https://github.com/longbridge/gpui-component#da4f93696dc2b2b4d91bcc42412b9053a3d24de8"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"gpui", "gpui",
@@ -3644,17 +3644,40 @@ dependencies = [
[[package]] [[package]]
name = "gpui-component-macros" name = "gpui-component-macros"
version = "0.5.1" version = "0.5.1"
source = "git+https://github.com/longbridge/gpui-component#b83e4a3a950cfe28a30e4b5a73ad0dd06a821593" source = "git+https://github.com/longbridge/gpui-component#da4f93696dc2b2b4d91bcc42412b9053a3d24de8"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.119", "syn 2.0.119",
] ]
[[package]]
name = "gpui_apple"
version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [
"anyhow",
"block",
"cbindgen",
"cocoa 0.26.0",
"collections",
"core-foundation 0.10.1",
"core-video",
"derive_more",
"etagere",
"foreign-types",
"gpui",
"image",
"log",
"metal",
"objc",
"parking_lot",
]
[[package]] [[package]]
name = "gpui_linux" name = "gpui_linux"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"accesskit", "accesskit",
"accesskit_unix", "accesskit_unix",
@@ -3706,7 +3729,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui_macos" name = "gpui_macos"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"accesskit", "accesskit",
"accesskit_macos", "accesskit_macos",
@@ -3714,21 +3737,18 @@ dependencies = [
"async-task", "async-task",
"block", "block",
"block2 0.6.2", "block2 0.6.2",
"cbindgen",
"cocoa 0.26.0", "cocoa 0.26.0",
"collections", "collections",
"core-foundation 0.10.1", "core-foundation 0.10.1",
"core-foundation-sys", "core-foundation-sys",
"core-graphics 0.24.0", "core-graphics 0.24.0",
"core-text", "core-text",
"core-video",
"ctor", "ctor",
"derive_more",
"dispatch2", "dispatch2",
"etagere",
"foreign-types", "foreign-types",
"futures", "futures",
"gpui", "gpui",
"gpui_apple",
"gpui_util", "gpui_util",
"image", "image",
"itertools 0.14.0", "itertools 0.14.0",
@@ -3755,7 +3775,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui_macros" name = "gpui_macros"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
@@ -3766,7 +3786,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui_platform" name = "gpui_platform"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"console_error_panic_hook", "console_error_panic_hook",
"gpui", "gpui",
@@ -3779,7 +3799,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui_shared_string" name = "gpui_shared_string"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"schemars", "schemars",
"serde", "serde",
@@ -3789,7 +3809,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui_util" name = "gpui_util"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"log", "log",
@@ -3799,7 +3819,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui_web" name = "gpui_web"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"console_error_panic_hook", "console_error_panic_hook",
@@ -3822,7 +3842,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui_wgpu" name = "gpui_wgpu"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytemuck", "bytemuck",
@@ -3852,7 +3872,7 @@ dependencies = [
[[package]] [[package]]
name = "gpui_windows" name = "gpui_windows"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"accesskit", "accesskit",
"accesskit_windows", "accesskit_windows",
@@ -4165,7 +4185,7 @@ dependencies = [
[[package]] [[package]]
name = "http_client" name = "http_client"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"async-compression", "async-compression",
@@ -4185,7 +4205,7 @@ dependencies = [
[[package]] [[package]]
name = "http_client_tls" name = "http_client_tls"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"rustls", "rustls",
"rustls-platform-verifier 0.5.3", "rustls-platform-verifier 0.5.3",
@@ -4899,9 +4919,9 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]] [[package]]
name = "libredox" name = "libredox"
version = "0.1.19" version = "0.1.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2026a5056764a10b2bf5d56488cba40da507f5493a6a429340e2004d9ed085fa" checksum = "28d0a00925a9f930d679b6789b721e3a7f9ed110f41b86d2497caa780c3a070a"
dependencies = [ dependencies = [
"libc", "libc",
] ]
@@ -5161,7 +5181,7 @@ dependencies = [
[[package]] [[package]]
name = "media" name = "media"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bindgen", "bindgen",
@@ -5309,9 +5329,9 @@ dependencies = [
[[package]] [[package]]
name = "negentropy" name = "negentropy"
version = "0.5.0" version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0efe882e02d206d8d279c20eb40e03baf7cb5136a1476dc084a324fbc3ec42d" checksum = "81c353b400a5503efdcf398f11a83fb7aa84f59f5d76fc4bf5bbc1e4f5366caa"
[[package]] [[package]]
name = "new_debug_unreachable" name = "new_debug_unreachable"
@@ -5376,8 +5396,8 @@ dependencies = [
[[package]] [[package]]
name = "nostr" name = "nostr"
version = "0.45.1" version = "0.45.2"
source = "git+https://github.com/rust-nostr/nostr#f0f52cf82e04824b7d3c5ac2f0bfc7bbeef37b19" source = "git+https://github.com/rust-nostr/nostr#0a10756496173b7c97d7aa611fb8663931d1eaad"
dependencies = [ dependencies = [
"aes", "aes",
"base64", "base64",
@@ -5403,7 +5423,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-connect" name = "nostr-connect"
version = "0.45.1" version = "0.45.1"
source = "git+https://github.com/rust-nostr/nostr#f0f52cf82e04824b7d3c5ac2f0bfc7bbeef37b19" source = "git+https://github.com/rust-nostr/nostr#0a10756496173b7c97d7aa611fb8663931d1eaad"
dependencies = [ dependencies = [
"async-utility", "async-utility",
"futures-core", "futures-core",
@@ -5417,7 +5437,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-database" name = "nostr-database"
version = "0.45.1" version = "0.45.1"
source = "git+https://github.com/rust-nostr/nostr#f0f52cf82e04824b7d3c5ac2f0bfc7bbeef37b19" source = "git+https://github.com/rust-nostr/nostr#0a10756496173b7c97d7aa611fb8663931d1eaad"
dependencies = [ dependencies = [
"nostr", "nostr",
"opaquerr", "opaquerr",
@@ -5426,7 +5446,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-gossip" name = "nostr-gossip"
version = "0.45.0" version = "0.45.0"
source = "git+https://github.com/rust-nostr/nostr#f0f52cf82e04824b7d3c5ac2f0bfc7bbeef37b19" source = "git+https://github.com/rust-nostr/nostr#0a10756496173b7c97d7aa611fb8663931d1eaad"
dependencies = [ dependencies = [
"nostr", "nostr",
"opaquerr", "opaquerr",
@@ -5435,7 +5455,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-gossip-memory" name = "nostr-gossip-memory"
version = "0.45.0" version = "0.45.0"
source = "git+https://github.com/rust-nostr/nostr#f0f52cf82e04824b7d3c5ac2f0bfc7bbeef37b19" source = "git+https://github.com/rust-nostr/nostr#0a10756496173b7c97d7aa611fb8663931d1eaad"
dependencies = [ dependencies = [
"indexmap", "indexmap",
"lru", "lru",
@@ -5447,7 +5467,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-lmdb" name = "nostr-lmdb"
version = "0.45.1" version = "0.45.1"
source = "git+https://github.com/rust-nostr/nostr#f0f52cf82e04824b7d3c5ac2f0bfc7bbeef37b19" source = "git+https://github.com/rust-nostr/nostr#0a10756496173b7c97d7aa611fb8663931d1eaad"
dependencies = [ dependencies = [
"async-utility", "async-utility",
"flatbuffers", "flatbuffers",
@@ -5462,7 +5482,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-memory" name = "nostr-memory"
version = "0.45.1" version = "0.45.1"
source = "git+https://github.com/rust-nostr/nostr#f0f52cf82e04824b7d3c5ac2f0bfc7bbeef37b19" source = "git+https://github.com/rust-nostr/nostr#0a10756496173b7c97d7aa611fb8663931d1eaad"
dependencies = [ dependencies = [
"btreecap", "btreecap",
"nostr", "nostr",
@@ -5473,7 +5493,7 @@ dependencies = [
[[package]] [[package]]
name = "nostr-sdk" name = "nostr-sdk"
version = "0.45.1" version = "0.45.1"
source = "git+https://github.com/rust-nostr/nostr#f0f52cf82e04824b7d3c5ac2f0bfc7bbeef37b19" source = "git+https://github.com/rust-nostr/nostr#0a10756496173b7c97d7aa611fb8663931d1eaad"
dependencies = [ dependencies = [
"async-utility", "async-utility",
"async-wsocket", "async-wsocket",
@@ -6209,7 +6229,7 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220"
[[package]] [[package]]
name = "perf" name = "perf"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"collections", "collections",
"serde", "serde",
@@ -6961,7 +6981,7 @@ dependencies = [
[[package]] [[package]]
name = "refineable" name = "refineable"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"derive_refineable", "derive_refineable",
] ]
@@ -7044,7 +7064,7 @@ dependencies = [
[[package]] [[package]]
name = "reqwest_client" name = "reqwest_client"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@@ -7445,7 +7465,7 @@ dependencies = [
[[package]] [[package]]
name = "scheduler" name = "scheduler"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"async-task", "async-task",
"backtrace", "backtrace",
@@ -8168,7 +8188,7 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]] [[package]]
name = "sum_tree" name = "sum_tree"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"heapless 0.9.3", "heapless 0.9.3",
"log", "log",
@@ -9517,7 +9537,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
[[package]] [[package]]
name = "util_macros" name = "util_macros"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"perf", "perf",
"quote", "quote",
@@ -9533,9 +9553,9 @@ dependencies = [
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.24.0" version = "1.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239" checksum = "2cefc03fd367c0c6d4305de1b312cf00248c4114f4a0418ce6a6af769e3b0bd9"
dependencies = [ dependencies = [
"getrandom 0.4.3", "getrandom 0.4.3",
"js-sys", "js-sys",
@@ -9744,9 +9764,9 @@ dependencies = [
[[package]] [[package]]
name = "wayland-backend" name = "wayland-backend"
version = "0.3.16" version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "016ccf01d1c58b6f8999612813e17c9b2390f7d70671428869913310f83f54b8" checksum = "38a91b4eaddff87b1cd1074985e3713da4af2c49742d1b356b2c01670a67a078"
dependencies = [ dependencies = [
"cc", "cc",
"downcast-rs", "downcast-rs",
@@ -11301,7 +11321,7 @@ checksum = "34b31d188d9d685a4f9c7b46d6e36631b07058d2cfe190267adce54dc230bf12"
[[package]] [[package]]
name = "zlog" name = "zlog"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",
@@ -11318,7 +11338,7 @@ checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b"
[[package]] [[package]]
name = "ztracing" name = "ztracing"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
dependencies = [ dependencies = [
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
@@ -11329,7 +11349,7 @@ dependencies = [
[[package]] [[package]]
name = "ztracing_macro" name = "ztracing_macro"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/zed-industries/zed#24e25552b1259d56a6fdd7956a419ed9e8a1a25e" source = "git+https://github.com/zed-industries/zed#8968bf78084f30809aa2ce1574a3be68ed02a513"
[[package]] [[package]]
name = "zune-core" name = "zune-core"
@@ -11401,9 +11421,9 @@ dependencies = [
[[package]] [[package]]
name = "zvariant_utils" name = "zvariant_utils"
version = "4.0.0" version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "629d80ece222cad20fe0e8741be493c4ab166acf3b85341bdc2cdbcfd8f3c2d6" checksum = "6b84ebb462416c27cdb97f2e7f5f0ccc844da1fe2ecc7121e1b690b41318bf42"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
+7
View File
@@ -78,6 +78,13 @@ impl Announcement {
pub fn addr(&self) -> crate::RepoAddr { pub fn addr(&self) -> crate::RepoAddr {
crate::repo_addr(self.owner, self.id.clone()) crate::repo_addr(self.owner, self.id.clone())
} }
/// The description of the repository, or a default if none is provided.
pub fn description(&self) -> SharedString {
self.description
.clone()
.unwrap_or(SharedString::from("No description"))
}
} }
#[cfg(test)] #[cfg(test)]
@@ -6,7 +6,7 @@
use gpui::prelude::*; use gpui::prelude::*;
use gpui::{AnyElement, Context, Entity, SharedString, WeakEntity, Window, div, px}; use gpui::{AnyElement, Context, Entity, SharedString, WeakEntity, Window, div, px};
use gpui_component::button::{Button, ButtonVariants}; use gpui_component::button::{Button, ButtonVariants};
use gpui_component::input::{Editor, EditorState, TabSize}; use gpui_component::input::{Editor, EditorState};
use gpui_component::list::ListItem; use gpui_component::list::ListItem;
use gpui_component::spinner::Spinner; use gpui_component::spinner::Spinner;
use gpui_component::text::{TextView, TextViewState}; use gpui_component::text::{TextView, TextViewState};
@@ -281,12 +281,9 @@ impl RepoDetailView {
) { ) {
let language = code_language(path.as_ref()).unwrap_or("text"); let language = code_language(path.as_ref()).unwrap_or("text");
let state = cx.new(|cx| { let state = cx.new(|cx| {
EditorState::new(language, window, cx) EditorState::new(window, cx)
.language(language)
.default_value(text) .default_value(text)
.tab_size(TabSize {
tab_size: 4,
hard_tabs: false,
})
.line_number(true) .line_number(true)
.folding(true) .folding(true)
}); });
+192 -260
View File
@@ -8,16 +8,15 @@ use assets::CustomIconName;
use gix::Repository; use gix::Repository;
use gpui::prelude::*; use gpui::prelude::*;
use gpui::{ use gpui::{
AnyElement, App, ClipboardItem, Context, Entity, EventEmitter, FocusHandle, Focusable, Pixels, AnyElement, App, Context, Entity, EventEmitter, FocusHandle, Focusable, Pixels, Render,
Render, SharedString, Size, Subscription, Task, WeakEntity, Window, div, px, size, SharedString, Size, Subscription, Task, WeakEntity, Window, div, px, size,
}; };
use gpui_component::avatar::{Avatar, AvatarGroup}; use gpui_component::avatar::{Avatar, AvatarGroup};
use gpui_component::button::{Button, ButtonVariants, DropdownButton}; use gpui_component::button::{Button, ButtonVariants};
use gpui_component::combobox::{ use gpui_component::combobox::{
Caret, Combobox, ComboboxEvent, ComboboxState, ComboboxTriggerContext, Caret, Combobox, ComboboxEvent, ComboboxState, ComboboxTriggerContext,
}; };
use gpui_component::dock::{DockArea, DockPlacement, Panel, PanelEvent}; use gpui_component::dock::{DockArea, DockPlacement, Panel, PanelEvent};
use gpui_component::menu::PopupMenuItem;
use gpui_component::searchable_list::SearchableVec; use gpui_component::searchable_list::SearchableVec;
use gpui_component::tab::{Tab, TabBar}; use gpui_component::tab::{Tab, TabBar};
use gpui_component::tag::Tag; use gpui_component::tag::Tag;
@@ -75,13 +74,8 @@ pub struct RepoDetailView {
/// Snapshot taken at open time, shown until the store's first refresh /// Snapshot taken at open time, shown until the store's first refresh
/// completes (and as a fallback while the store has no announcement). /// completes (and as a fallback while the store has no announcement).
initial: Announcement, initial: Announcement,
/// Latest announcement from the store, cached so `render` (which runs /// Per-repository nostr store (announcement, issues, PRs, statuses).
/// every frame) does not re-read and re-clone the store's copy. store: Entity<RepoStore>,
announcement: Option<Announcement>,
/// Relay/web URLs of [`Self::announcement`] as display strings, for the
/// header dropdowns; `Rc` so the menu builders clone cheaply per frame.
relays: Rc<Vec<SharedString>>,
web: Rc<Vec<SharedString>>,
/// File explorer state (worktree of the local clone). /// File explorer state (worktree of the local clone).
tree_state: Entity<TreeState>, tree_state: Entity<TreeState>,
/// Root of the local clone, for reading files on demand. /// Root of the local clone, for reading files on demand.
@@ -135,8 +129,7 @@ pub struct RepoDetailView {
/// In-flight tasks; finished tasks are pruned on every push, so the vec /// In-flight tasks; finished tasks are pruned on every push, so the vec
/// stays bounded by the number of concurrent loads. /// stays bounded by the number of concurrent loads.
tasks: Vec<Task<Result<(), Error>>>, tasks: Vec<Task<Result<(), Error>>>,
/// Subscriptions keeping the selectors' confirm events and the store's /// Subscriptions keeping the selectors' confirm events alive.
/// refreshes alive.
_subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
} }
@@ -170,36 +163,7 @@ impl RepoDetailView {
.searchable(true) .searchable(true)
}); });
// Cache the announcement for the header: the store only changes it let subscriptions = vec![
// during debounced refreshes, but `render` runs every frame. The
// observe subscription owns the store for the view's lifetime.
let subscription = cx.observe(&store, |this, store, cx| {
let fresh = store.read(cx).announcement.clone();
if this.announcement == fresh {
return;
}
this.announcement = fresh;
// The header falls back to the open-time snapshot while the
// store has no announcement; keep its dropdown lists in sync.
let announcement = this.announcement.as_ref().unwrap_or(&this.initial);
this.relays = Rc::new(
announcement
.relays
.iter()
.map(|relay| relay.to_string().into())
.collect(),
);
this.web = Rc::new(
announcement
.web
.iter()
.map(|url| url.to_string().into())
.collect(),
);
cx.notify();
});
let mut subscriptions = vec![
cx.subscribe_in(&branch_select, window, |this, _state, event, window, cx| { cx.subscribe_in(&branch_select, window, |this, _state, event, window, cx| {
// `Change` fires only when the selection actually changed // `Change` fires only when the selection actually changed
// (picking the already-selected branch emits nothing), so a // (picking the already-selected branch emits nothing), so a
@@ -218,36 +182,16 @@ impl RepoDetailView {
} }
}), }),
]; ];
subscriptions.push(subscription);
// Defer loading the repository until the window is ready. // Defer loading the repository until the window is ready.
cx.defer_in(window, |this, window, cx| { cx.defer_in(window, |this, window, cx| {
this.load_repo(window, cx); this.load_repo(window, cx);
}); });
// Header dropdowns of the open-time snapshot, until the store's
// first refresh replaces them.
let relays = Rc::new(
initial
.relays
.iter()
.map(|relay| relay.to_string().into())
.collect(),
);
let web = Rc::new(
initial
.web
.iter()
.map(|url| url.to_string().into())
.collect(),
);
Self { Self {
initial, initial,
dock_area, dock_area,
announcement: None, store,
relays,
web,
tree_state, tree_state,
worktree: None, worktree: None,
md: None, md: None,
@@ -693,7 +637,7 @@ impl RepoDetailView {
}; };
// Same display name as the repo detail panel's title. // Same display name as the repo detail panel's title.
let repo_name = self.display_name(); let repo_name = self.display_name(cx);
let panel = let panel =
cx.new(|cx| CommitDiffView::new(worktree, repo_name, commit_id.into(), window, cx)); cx.new(|cx| CommitDiffView::new(worktree, repo_name, commit_id.into(), window, cx));
@@ -703,6 +647,18 @@ impl RepoDetailView {
}); });
} }
/// Open the issue detail view (not implemented yet).
fn open_issue_detail(&mut self, _window: &mut Window, _cx: &mut Context<Self>) {
// TODO: open a per-issue detail view in the dock area, like
// [`Self::open_commit_diff`].
}
/// Open the pull request detail view (not implemented yet).
fn open_pull_request_detail(&mut self, _window: &mut Window, _cx: &mut Context<Self>) {
// TODO: open a per-PR detail view in the dock area, like
// [`Self::open_commit_diff`].
}
/// Check out `name` (a branch or tag picked in the header) and refresh /// Check out `name` (a branch or tag picked in the header) and refresh
/// the explorer once the switch completes. /// the explorer once the switch completes.
fn switch_ref( fn switch_ref(
@@ -930,164 +886,31 @@ impl RepoDetailView {
} }
/// The latest announcement from the store, or the open-time snapshot. /// The latest announcement from the store, or the open-time snapshot.
fn announcement(&self) -> &Announcement { fn announcement<'a>(&'a self, cx: &'a App) -> &'a Announcement {
self.announcement.as_ref().unwrap_or(&self.initial) self.store
.read(cx)
.announcement
.as_ref()
.unwrap_or(&self.initial)
} }
/// Display name: the announcement's name, or the ID if no name is set. /// Display name: the announcement's name, or the ID if no name is set.
fn display_name(&self) -> SharedString { fn display_name(&self, cx: &App) -> SharedString {
let announcement = self.announcement(); let announcement = self.announcement(cx);
announcement announcement
.name .name
.clone() .clone()
.unwrap_or_else(|| SharedString::from(announcement.id.clone())) .unwrap_or_else(|| SharedString::from(announcement.id.clone()))
} }
/// Horizontal list of everyone who maintains the repository: the owner
/// shown in full, and any additional maintainers as a compact overlapping avatar group.
fn render_maintainers(&self, cx: &mut Context<Self>) -> AnyElement {
let announcement = self.announcement();
let profile_store = ProfileStore::global(cx);
let mut seen = HashSet::new();
let rest: Vec<_> = announcement
.maintainers
.iter()
.copied()
.filter(|key| *key != announcement.owner && seen.insert(*key))
.collect();
let owner = profile_store.read(cx).get(&announcement.owner);
let owner_name = owner.name();
let owner_picture = owner.picture();
h_flex()
.w_full()
.gap_3()
.items_center()
.flex_wrap()
.child(
h_flex()
.gap_1()
.items_center()
.child(
Avatar::new()
.name(owner_name.clone())
.when_some(owner_picture, |this, url| this.src(url))
.small(),
)
.child(div().text_xs().whitespace_nowrap().child(owner_name)),
)
.when(!rest.is_empty(), |this| {
this.child(AvatarGroup::new().small().limit(5).ellipsis().children(
rest.into_iter().map(|key| {
let profile = profile_store.read(cx).get(&key);
Avatar::new()
.name(profile.name())
.when_some(profile.picture(), |this, url| this.src(url))
}),
))
})
.into_any_element()
}
}
impl Panel for RepoDetailView {
fn panel_name(&self) -> &'static str {
"repo_detail"
}
fn title(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
self.display_name()
}
}
/// Read the worktree state of `repo` (no network): entries, README, refs
/// and HEAD commit. The tree is built off the main thread; the seeds are
/// plain owned strings and convert to `TreeItem`s (which hold `Rc` state)
/// on the main thread.
fn load_repo_data(repo: &Repository) -> Result<RepoData, Error> {
let entries = signed_git::worktree_entries(repo)?;
let tree = build_tree_items(&entries);
let readme_path = signed_git::find_readme(repo)?;
let readme = match &readme_path {
Some(path) => signed_git::worktree_read(repo, path)?,
None => None,
};
let worktree = repo.workdir().map(Path::to_path_buf);
// Ref listing is auxiliary UI: a broken ref must not prevent the
// explorer from loading, so failures degrade to empty selectors.
let (branches, tags, current_branch) = match &worktree {
Some(_) => (
signed_git::repo_branches(repo).unwrap_or_default(),
signed_git::repo_tags(repo).unwrap_or_default(),
signed_git::current_branch(repo).unwrap_or(None),
),
None => (Vec::new(), Vec::new(), None),
};
let head_commit = signed_git::head_commit(repo).unwrap_or(None);
Ok(RepoData {
tree,
readme_path,
readme,
worktree,
branches,
tags,
current_branch,
head_commit,
})
}
impl EventEmitter<PanelEvent> for RepoDetailView {}
impl Focusable for RepoDetailView {
fn focus_handle(&self, _cx: &App) -> FocusHandle {
self.focus_handle.clone()
}
}
impl Render for RepoDetailView {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let tree_state = self.tree_state.clone();
let view = cx.entity().downgrade();
let pane_title = self
.selected_file
.clone()
.or_else(|| self.readme_name.clone())
.unwrap_or_else(|| "Overview".into());
v_flex()
.id("repo")
.size_full()
.child(self.render_header(cx))
.child(match self.active_tab {
0 => h_flex()
.flex_1()
.w_full()
.overflow_hidden()
.child(Self::render_tree_column(tree_state, view, cx))
.child(self.render_content_column(pane_title, cx))
.into_any_element(),
_ => self.render_commits_tab(cx),
})
}
}
impl RepoDetailView {
/// Header: repository name and description, relay/web/clone buttons, the
/// Files/Commits tab bar and the branch/tag selectors with the
/// latest-commit button.
fn render_header(&self, cx: &mut Context<Self>) -> AnyElement { fn render_header(&self, cx: &mut Context<Self>) -> AnyElement {
let announcement = self.announcement(); let store = self.store.read(cx);
let relays = self.relays.clone(); let announcement = store.announcement.as_ref().unwrap_or(&self.initial);
let web = self.web.clone(); let issue_count = store.issues.len();
let pull_request_count = store.pull_requests.len();
let name = self.display_name(); let name = self.display_name(cx);
let description = announcement let description = announcement.description();
.description
.clone()
.unwrap_or(SharedString::from("No description"));
let commits_count = self.all_commits.as_ref().map(|list| list.total); let commits_count = self.all_commits.as_ref().map(|list| list.total);
let worktree_empty = self.switching_ref || self.worktree.is_none(); let worktree_empty = self.switching_ref || self.worktree.is_none();
@@ -1140,58 +963,36 @@ impl RepoDetailView {
.gap_2() .gap_2()
.justify_end() .justify_end()
.child( .child(
DropdownButton::new("relays") Button::new("issues")
.button( .child(
Button::new("relay-trigger") h_flex()
.label(format!("{} relays", relays.len())) .gap_2()
.small() .text_sm()
.ghost(), .child(SharedString::from("Issues"))
.child(Tag::new().xsmall().child(SharedString::from(
issue_count.to_string(),
))),
) )
.dropdown_menu(move |menu, _window, _cx| { .outline()
let mut menu = menu; .on_click(cx.listener(|this, _event, window, cx| {
if relays.is_empty() { this.open_issue_detail(window, cx);
return menu.item( })),
PopupMenuItem::new("No relays").disabled(true),
);
}
for relay in relays.iter() {
let url = relay.to_string();
menu = menu.item(
PopupMenuItem::new(url.clone()).on_click(
move |_, _, cx| {
cx.write_to_clipboard(
ClipboardItem::new_string(url.clone()),
);
},
),
);
}
menu
}),
) )
.child( .child(
DropdownButton::new("web") Button::new("prs")
.button( .child(
Button::new("web-trigger") h_flex()
.label("Websites") .gap_2()
.small() .text_sm()
.ghost(), .child(SharedString::from("Pull Requests"))
.child(Tag::new().xsmall().child(SharedString::from(
pull_request_count.to_string(),
))),
) )
.dropdown_menu(move |menu, _window, _cx| { .outline()
let mut menu = menu; .on_click(cx.listener(|this, _event, window, cx| {
if web.is_empty() { this.open_pull_request_detail(window, cx);
return menu })),
.item(PopupMenuItem::new("No web").disabled(true));
}
for url in web.iter() {
let href = url.to_string();
menu = menu.item(
PopupMenuItem::new(href.clone())
.on_click(move |_, _, cx| cx.open_url(&href)),
);
}
menu
}),
) )
.child( .child(
Button::new("link") Button::new("link")
@@ -1306,4 +1107,135 @@ impl RepoDetailView {
) )
.into_any_element() .into_any_element()
} }
/// Horizontal list of everyone who maintains the repository: the owner
/// shown in full, and any additional maintainers as a compact overlapping avatar group.
fn render_maintainers(&self, cx: &mut Context<Self>) -> AnyElement {
let announcement = self.announcement(cx);
let profile_store = ProfileStore::global(cx);
let mut seen = HashSet::new();
let rest: Vec<_> = announcement
.maintainers
.iter()
.copied()
.filter(|key| *key != announcement.owner && seen.insert(*key))
.collect();
let owner = profile_store.read(cx).get(&announcement.owner);
let owner_name = owner.name();
let owner_picture = owner.picture();
h_flex()
.w_full()
.gap_3()
.items_center()
.flex_wrap()
.child(
h_flex()
.gap_1()
.items_center()
.child(
Avatar::new()
.name(owner_name.clone())
.when_some(owner_picture, |this, url| this.src(url))
.small(),
)
.child(div().text_xs().whitespace_nowrap().child(owner_name)),
)
.when(!rest.is_empty(), |this| {
this.child(AvatarGroup::new().small().limit(5).ellipsis().children(
rest.into_iter().map(|key| {
let profile = profile_store.read(cx).get(&key);
Avatar::new()
.name(profile.name())
.when_some(profile.picture(), |this, url| this.src(url))
}),
))
})
.into_any_element()
}
}
impl Panel for RepoDetailView {
fn panel_name(&self) -> &'static str {
"repo_detail"
}
fn title(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
self.display_name(cx)
}
}
impl EventEmitter<PanelEvent> for RepoDetailView {}
impl Focusable for RepoDetailView {
fn focus_handle(&self, _cx: &App) -> FocusHandle {
self.focus_handle.clone()
}
}
impl Render for RepoDetailView {
fn render(&mut self, _window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let tree_state = self.tree_state.clone();
let view = cx.entity().downgrade();
let pane_title = self
.selected_file
.clone()
.or_else(|| self.readme_name.clone())
.unwrap_or_else(|| "Overview".into());
v_flex()
.id("repo")
.size_full()
.child(self.render_header(cx))
.child(match self.active_tab {
0 => h_flex()
.flex_1()
.w_full()
.overflow_hidden()
.child(Self::render_tree_column(tree_state, view, cx))
.child(self.render_content_column(pane_title, cx))
.into_any_element(),
_ => self.render_commits_tab(cx),
})
}
}
/// Read the worktree state of `repo` (no network): entries, README, refs
/// and HEAD commit. The tree is built off the main thread; the seeds are
/// plain owned strings and convert to `TreeItem`s (which hold `Rc` state)
/// on the main thread.
fn load_repo_data(repo: &Repository) -> Result<RepoData, Error> {
let entries = signed_git::worktree_entries(repo)?;
let tree = build_tree_items(&entries);
let readme_path = signed_git::find_readme(repo)?;
let readme = match &readme_path {
Some(path) => signed_git::worktree_read(repo, path)?,
None => None,
};
let worktree = repo.workdir().map(Path::to_path_buf);
// Ref listing is auxiliary UI: a broken ref must not prevent the
// explorer from loading, so failures degrade to empty selectors.
let (branches, tags, current_branch) = match &worktree {
Some(_) => (
signed_git::repo_branches(repo).unwrap_or_default(),
signed_git::repo_tags(repo).unwrap_or_default(),
signed_git::current_branch(repo).unwrap_or(None),
),
None => (Vec::new(), Vec::new(), None),
};
let head_commit = signed_git::head_commit(repo).unwrap_or(None);
Ok(RepoData {
tree,
readme_path,
readme,
worktree,
branches,
tags,
current_branch,
head_commit,
})
} }