wip: refactor
This commit is contained in:
115
Cargo.lock
generated
115
Cargo.lock
generated
@@ -410,7 +410,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "async-wsocket"
|
name = "async-wsocket"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
source = "git+https://github.com/yukibtc/async-wsocket?rev=27f606af6b2028634022a97b5e56c332dfe3f611#27f606af6b2028634022a97b5e56c332dfe3f611"
|
source = "git+https://github.com/yukibtc/async-wsocket?rev=259c0bc372e7d60d94827b484178bf995afdcbe6#259c0bc372e7d60d94827b484178bf995afdcbe6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-utility",
|
"async-utility",
|
||||||
"futures",
|
"futures",
|
||||||
@@ -548,18 +548,18 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-set"
|
name = "bit-set"
|
||||||
version = "0.6.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f0481a0e032742109b1133a095184ee93d88f3dc9e0d28a5d033dc77a073f44f"
|
checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bit-vec",
|
"bit-vec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit-vec"
|
name = "bit-vec"
|
||||||
version = "0.7.0"
|
version = "0.8.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d2c54ff287cfc0a34f38a6b832ea1bd8e448a330b3e40a50859e6488bee07f22"
|
checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bit_field"
|
name = "bit_field"
|
||||||
@@ -661,7 +661,7 @@ checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "blade-graphics"
|
name = "blade-graphics"
|
||||||
version = "0.5.0"
|
version = "0.5.0"
|
||||||
source = "git+https://github.com/kvark/blade?rev=e142a3a5e678eb6a13e642ad8401b1f3aa38e969#e142a3a5e678eb6a13e642ad8401b1f3aa38e969"
|
source = "git+https://github.com/kvark/blade?rev=099555282605c7c4cca9e66a8f40148298347f80#099555282605c7c4cca9e66a8f40148298347f80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ash",
|
"ash",
|
||||||
"ash-window",
|
"ash-window",
|
||||||
@@ -691,7 +691,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "blade-macros"
|
name = "blade-macros"
|
||||||
version = "0.3.0"
|
version = "0.3.0"
|
||||||
source = "git+https://github.com/kvark/blade?rev=e142a3a5e678eb6a13e642ad8401b1f3aa38e969#e142a3a5e678eb6a13e642ad8401b1f3aa38e969"
|
source = "git+https://github.com/kvark/blade?rev=099555282605c7c4cca9e66a8f40148298347f80#099555282605c7c4cca9e66a8f40148298347f80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -701,7 +701,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "blade-util"
|
name = "blade-util"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/kvark/blade?rev=e142a3a5e678eb6a13e642ad8401b1f3aa38e969#e142a3a5e678eb6a13e642ad8401b1f3aa38e969"
|
source = "git+https://github.com/kvark/blade?rev=099555282605c7c4cca9e66a8f40148298347f80#099555282605c7c4cca9e66a8f40148298347f80"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"blade-graphics",
|
"blade-graphics",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
@@ -861,9 +861,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.4"
|
version = "1.2.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9157bbaa6b165880c27a4293a474c91cdcf265cc68cc829bf10be0964a391caf"
|
checksum = "c31a0499c1dc64f458ad13872de75c0eb7e3fdb0e67964610c914b034fc5956e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -1040,7 +1040,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "collections"
|
name = "collections"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#af50261ae240a2c44bc742f434be46032e47256e"
|
source = "git+https://github.com/zed-industries/zed#3632b36fde4c4e73eadc7e231d7b040a3b7fb55b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rustc-hash 1.1.0",
|
"rustc-hash 1.1.0",
|
||||||
]
|
]
|
||||||
@@ -1379,7 +1379,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#af50261ae240a2c44bc742f434be46032e47256e"
|
source = "git+https://github.com/zed-industries/zed#3632b36fde4c4e73eadc7e231d7b040a3b7fb55b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2104,7 +2104,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "gpui"
|
name = "gpui"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#af50261ae240a2c44bc742f434be46032e47256e"
|
source = "git+https://github.com/zed-industries/zed#3632b36fde4c4e73eadc7e231d7b040a3b7fb55b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"as-raw-xcb-connection",
|
"as-raw-xcb-connection",
|
||||||
@@ -2189,7 +2189,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#af50261ae240a2c44bc742f434be46032e47256e"
|
source = "git+https://github.com/zed-industries/zed#3632b36fde4c4e73eadc7e231d7b040a3b7fb55b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -2400,7 +2400,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#af50261ae240a2c44bc742f434be46032e47256e"
|
source = "git+https://github.com/zed-industries/zed#3632b36fde4c4e73eadc7e231d7b040a3b7fb55b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -2421,9 +2421,9 @@ checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper"
|
name = "hyper"
|
||||||
version = "1.5.1"
|
version = "1.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f"
|
checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes",
|
"bytes",
|
||||||
"futures-channel",
|
"futures-channel",
|
||||||
@@ -2441,9 +2441,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hyper-rustls"
|
name = "hyper-rustls"
|
||||||
version = "0.27.3"
|
version = "0.27.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333"
|
checksum = "f6884a48c6826ec44f524c7456b163cebe9e55a18d7b5e307cb4f100371cc767"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures-util",
|
"futures-util",
|
||||||
"http",
|
"http",
|
||||||
@@ -2822,7 +2822,7 @@ dependencies = [
|
|||||||
"dbus-secret-service",
|
"dbus-secret-service",
|
||||||
"log",
|
"log",
|
||||||
"security-framework 2.11.1",
|
"security-framework 2.11.1",
|
||||||
"security-framework 3.0.1",
|
"security-framework 3.1.0",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2878,9 +2878,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.168"
|
version = "0.2.169"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
|
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libdbus-sys"
|
name = "libdbus-sys"
|
||||||
@@ -3065,7 +3065,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "media"
|
name = "media"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#af50261ae240a2c44bc742f434be46032e47256e"
|
source = "git+https://github.com/zed-industries/zed#3632b36fde4c4e73eadc7e231d7b040a3b7fb55b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bindgen",
|
"bindgen",
|
||||||
@@ -3102,9 +3102,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "metal"
|
name = "metal"
|
||||||
version = "0.29.0"
|
version = "0.30.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/gfx-rs/metal-rs?rev=ef768ff9d742ae6a0f4e83ddc8031264e7d460c4#ef768ff9d742ae6a0f4e83ddc8031264e7d460c4"
|
||||||
checksum = "7ecfd3296f8c56b7c1f6fbac3c71cefa9d78ce009850c45000015f206dc7fa21"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"block",
|
"block",
|
||||||
@@ -3129,9 +3128,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.8.0"
|
version = "0.8.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1"
|
checksum = "4ffbe83022cedc1d264172192511ae958937694cd57ce297164951b8b3568394"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"adler2",
|
"adler2",
|
||||||
"simd-adler32",
|
"simd-adler32",
|
||||||
@@ -3156,9 +3155,8 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "naga"
|
name = "naga"
|
||||||
version = "22.1.0"
|
version = "23.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "git+https://github.com/gfx-rs/wgpu?rev=1a643291c2e8854ba7e4f5445a4388202731bfa1#1a643291c2e8854ba7e4f5445a4388202731bfa1"
|
||||||
checksum = "8bd5a652b6faf21496f2cfd88fc49989c8db0825d1f6746b1a71a6ede24a63ad"
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"bit-set",
|
"bit-set",
|
||||||
@@ -3234,7 +3232,7 @@ checksum = "0676bb32a98c1a483ce53e500a81ad9c3d5b3f7c920c28c24e9cb0980d0b5bc8"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr"
|
name = "nostr"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#c616b2f598ef65e8d7e2b6b0959aa28e9c5d9d41"
|
source = "git+https://github.com/rust-nostr/nostr#2efdc69ad385b51b1c5f93706bfeeff5b6dd4d41"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aes",
|
"aes",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
@@ -3265,7 +3263,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-database"
|
name = "nostr-database"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#c616b2f598ef65e8d7e2b6b0959aa28e9c5d9d41"
|
source = "git+https://github.com/rust-nostr/nostr#2efdc69ad385b51b1c5f93706bfeeff5b6dd4d41"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"flatbuffers",
|
"flatbuffers",
|
||||||
@@ -3276,7 +3274,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-lmdb"
|
name = "nostr-lmdb"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#c616b2f598ef65e8d7e2b6b0959aa28e9c5d9d41"
|
source = "git+https://github.com/rust-nostr/nostr#2efdc69ad385b51b1c5f93706bfeeff5b6dd4d41"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-utility",
|
"async-utility",
|
||||||
"heed",
|
"heed",
|
||||||
@@ -3288,7 +3286,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-relay-pool"
|
name = "nostr-relay-pool"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#c616b2f598ef65e8d7e2b6b0959aa28e9c5d9d41"
|
source = "git+https://github.com/rust-nostr/nostr#2efdc69ad385b51b1c5f93706bfeeff5b6dd4d41"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-utility",
|
"async-utility",
|
||||||
"async-wsocket",
|
"async-wsocket",
|
||||||
@@ -3304,7 +3302,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-sdk"
|
name = "nostr-sdk"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#c616b2f598ef65e8d7e2b6b0959aa28e9c5d9d41"
|
source = "git+https://github.com/rust-nostr/nostr#2efdc69ad385b51b1c5f93706bfeeff5b6dd4d41"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-utility",
|
"async-utility",
|
||||||
"lnurl-pay",
|
"lnurl-pay",
|
||||||
@@ -3313,7 +3311,6 @@ dependencies = [
|
|||||||
"nostr-lmdb",
|
"nostr-lmdb",
|
||||||
"nostr-relay-pool",
|
"nostr-relay-pool",
|
||||||
"nostr-zapper",
|
"nostr-zapper",
|
||||||
"thiserror 1.0.69",
|
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@@ -3321,7 +3318,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "nostr-zapper"
|
name = "nostr-zapper"
|
||||||
version = "0.37.0"
|
version = "0.37.0"
|
||||||
source = "git+https://github.com/rust-nostr/nostr#c616b2f598ef65e8d7e2b6b0959aa28e9c5d9d41"
|
source = "git+https://github.com/rust-nostr/nostr#2efdc69ad385b51b1c5f93706bfeeff5b6dd4d41"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"nostr",
|
"nostr",
|
||||||
@@ -3916,7 +3913,7 @@ dependencies = [
|
|||||||
"rustc-hash 2.1.0",
|
"rustc-hash 2.1.0",
|
||||||
"rustls",
|
"rustls",
|
||||||
"socket2 0.5.8",
|
"socket2 0.5.8",
|
||||||
"thiserror 2.0.7",
|
"thiserror 2.0.8",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
@@ -3935,7 +3932,7 @@ dependencies = [
|
|||||||
"rustls",
|
"rustls",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"slab",
|
"slab",
|
||||||
"thiserror 2.0.7",
|
"thiserror 2.0.8",
|
||||||
"tinyvec",
|
"tinyvec",
|
||||||
"tracing",
|
"tracing",
|
||||||
"web-time",
|
"web-time",
|
||||||
@@ -3943,9 +3940,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "quinn-udp"
|
name = "quinn-udp"
|
||||||
version = "0.5.8"
|
version = "0.5.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "52cd4b1eff68bf27940dd39811292c49e007f4d0b4c357358dc9b0197be6b527"
|
checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg_aliases 0.2.1",
|
"cfg_aliases 0.2.1",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -4121,7 +4118,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "refineable"
|
name = "refineable"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#af50261ae240a2c44bc742f434be46032e47256e"
|
source = "git+https://github.com/zed-industries/zed#3632b36fde4c4e73eadc7e231d7b040a3b7fb55b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"derive_refineable",
|
"derive_refineable",
|
||||||
]
|
]
|
||||||
@@ -4248,7 +4245,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#af50261ae240a2c44bc742f434be46032e47256e"
|
source = "git+https://github.com/zed-industries/zed#3632b36fde4c4e73eadc7e231d7b040a3b7fb55b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"bytes",
|
"bytes",
|
||||||
@@ -4417,7 +4414,7 @@ dependencies = [
|
|||||||
"openssl-probe",
|
"openssl-probe",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"schannel",
|
"schannel",
|
||||||
"security-framework 3.0.1",
|
"security-framework 3.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -4632,9 +4629,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "3.0.1"
|
version = "3.1.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e1415a607e92bec364ea2cf9264646dcce0f91e6d65281bd6f2819cca3bf39c8"
|
checksum = "81d3f8c9bfcc3cbb6b0179eb57042d75b1582bdc65c3cb95f3fa999509c03cbc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.6.0",
|
"bitflags 2.6.0",
|
||||||
"core-foundation 0.10.0",
|
"core-foundation 0.10.0",
|
||||||
@@ -4645,9 +4642,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework-sys"
|
name = "security-framework-sys"
|
||||||
version = "2.12.1"
|
version = "2.13.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2"
|
checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"core-foundation-sys",
|
"core-foundation-sys",
|
||||||
"libc",
|
"libc",
|
||||||
@@ -4662,7 +4659,7 @@ checksum = "c2fdfc24bc566f839a2da4c4295b82db7d25a24253867d5c64355abb5799bdbe"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "semantic_version"
|
name = "semantic_version"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#af50261ae240a2c44bc742f434be46032e47256e"
|
source = "git+https://github.com/zed-industries/zed#3632b36fde4c4e73eadc7e231d7b040a3b7fb55b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"serde",
|
"serde",
|
||||||
@@ -4988,7 +4985,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#af50261ae240a2c44bc742f434be46032e47256e"
|
source = "git+https://github.com/zed-industries/zed#3632b36fde4c4e73eadc7e231d7b040a3b7fb55b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"arrayvec",
|
"arrayvec",
|
||||||
"log",
|
"log",
|
||||||
@@ -5263,11 +5260,11 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror"
|
name = "thiserror"
|
||||||
version = "2.0.7"
|
version = "2.0.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "93605438cbd668185516ab499d589afb7ee1859ea3d5fc8f6b0755e1c7443767"
|
checksum = "08f5383f3e0071702bf93ab5ee99b52d26936be9dedd9413067cbdcddcb6141a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"thiserror-impl 2.0.7",
|
"thiserror-impl 2.0.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -5283,9 +5280,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "thiserror-impl"
|
name = "thiserror-impl"
|
||||||
version = "2.0.7"
|
version = "2.0.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e1d8749b4531af2117677a5fcd12b1348a3fe2b81e36e61ffeac5c4aa3273e36"
|
checksum = "f2f357fcec90b3caef6623a099691be676d033b40a058ac95d2a6ade6fa0c943"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
@@ -5622,9 +5619,9 @@ checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi"
|
name = "unicode-bidi"
|
||||||
version = "0.3.17"
|
version = "0.3.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893"
|
checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-bidi-mirroring"
|
name = "unicode-bidi-mirroring"
|
||||||
@@ -5783,7 +5780,7 @@ checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be"
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "util"
|
name = "util"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://github.com/zed-industries/zed#af50261ae240a2c44bc742f434be46032e47256e"
|
source = "git+https://github.com/zed-industries/zed#3632b36fde4c4e73eadc7e231d7b040a3b7fb55b"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-fs 1.6.0",
|
"async-fs 1.6.0",
|
||||||
|
|||||||
@@ -102,37 +102,39 @@ async fn main() {
|
|||||||
} = message
|
} = message
|
||||||
{
|
{
|
||||||
if event.kind == Kind::GiftWrap {
|
if event.kind == Kind::GiftWrap {
|
||||||
if let Ok(UnwrappedGift { rumor, .. }) =
|
match client.unwrap_gift_wrap(&event).await {
|
||||||
client.unwrap_gift_wrap(&event).await
|
Ok(UnwrappedGift { rumor, .. }) => {
|
||||||
{
|
let mut rumor_clone = rumor.clone();
|
||||||
let mut rumor_clone = rumor.clone();
|
|
||||||
|
|
||||||
// Compute event id if not exist
|
// Compute event id if not exist
|
||||||
rumor_clone.ensure_id();
|
rumor_clone.ensure_id();
|
||||||
|
|
||||||
if let Some(id) = rumor_clone.id {
|
if let Some(id) = rumor_clone.id {
|
||||||
let ev = Event::new(
|
let ev = Event::new(
|
||||||
id,
|
id,
|
||||||
rumor_clone.pubkey,
|
rumor_clone.pubkey,
|
||||||
rumor_clone.created_at,
|
rumor_clone.created_at,
|
||||||
rumor_clone.kind,
|
rumor_clone.kind,
|
||||||
rumor_clone.tags,
|
rumor_clone.tags,
|
||||||
rumor_clone.content,
|
rumor_clone.content,
|
||||||
sig,
|
sig,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Save rumor to database to further query
|
// Save rumor to database to further query
|
||||||
if let Err(e) = client.database().save_event(&ev).await {
|
if let Err(e) = client.database().save_event(&ev).await {
|
||||||
println!("Save error: {}", e);
|
println!("Save error: {}", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send event back to channel
|
// Send event back to channel
|
||||||
if subscription_id == new_message {
|
if subscription_id == new_message {
|
||||||
if let Err(e) = signal_tx.send(Signal::RecvEvent(ev)).await {
|
if let Err(e) = signal_tx.send(Signal::RecvEvent(ev)).await
|
||||||
println!("Error: {}", e)
|
{
|
||||||
|
println!("Error: {}", e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Err(e) => println!("Error: {}", e),
|
||||||
}
|
}
|
||||||
} else if event.kind == Kind::Metadata {
|
} else if event.kind == Kind::Metadata {
|
||||||
if let Err(e) = signal_tx.send(Signal::RecvMetadata(event.pubkey)).await {
|
if let Err(e) = signal_tx.send(Signal::RecvMetadata(event.pubkey)).await {
|
||||||
|
|||||||
@@ -24,12 +24,9 @@ impl Form {
|
|||||||
.cleanable()
|
.cleanable()
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.subscribe(&input, move |form, text_input, input_event, cx| {
|
cx.subscribe(&input, move |form, _, input_event, cx| {
|
||||||
if let InputEvent::PressEnter = input_event {
|
if let InputEvent::PressEnter = input_event {
|
||||||
let content = text_input.read(cx).text().to_string();
|
form.send_message(cx);
|
||||||
// TODO: clean up content
|
|
||||||
|
|
||||||
form.send_message(content, cx);
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
@@ -37,28 +34,45 @@ impl Form {
|
|||||||
Self { to, input }
|
Self { to, input }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_message(&mut self, content: String, cx: &mut ViewContext<Self>) {
|
fn send_message(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
let send_to = self.to;
|
let send_to = self.to;
|
||||||
|
let content = self.input.read(cx).text().to_string();
|
||||||
let content_clone = content.clone();
|
let content_clone = content.clone();
|
||||||
|
|
||||||
|
let async_input = self.input.clone();
|
||||||
|
let mut async_cx = cx.to_async();
|
||||||
|
|
||||||
cx.foreground_executor()
|
cx.foreground_executor()
|
||||||
.spawn(async move {
|
.spawn(async move {
|
||||||
let client = get_client();
|
let client = get_client();
|
||||||
let signer = client.signer().await.unwrap();
|
|
||||||
let public_key = signer.get_public_key().await.unwrap();
|
|
||||||
|
|
||||||
match client.send_private_msg(send_to, content, vec![]).await {
|
async_cx
|
||||||
Ok(_) => {
|
.background_executor()
|
||||||
// Send a copy to yourself
|
.spawn(async move {
|
||||||
if let Err(_e) = client
|
let signer = client.signer().await.unwrap();
|
||||||
.send_private_msg(public_key, content_clone, vec![])
|
let public_key = signer.get_public_key().await.unwrap();
|
||||||
|
|
||||||
|
// Send message to all members
|
||||||
|
if client
|
||||||
|
.send_private_msg(send_to, content, vec![])
|
||||||
.await
|
.await
|
||||||
|
.is_ok()
|
||||||
{
|
{
|
||||||
todo!()
|
// Send a copy to yourself
|
||||||
|
_ = client
|
||||||
|
.send_private_msg(
|
||||||
|
public_key,
|
||||||
|
content_clone,
|
||||||
|
vec![Tag::public_key(send_to)],
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
Err(_) => todo!(),
|
.await;
|
||||||
}
|
|
||||||
|
_ = async_cx.update_view(&async_input, |input, cx| {
|
||||||
|
input.set_text("", cx);
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.detach();
|
.detach();
|
||||||
}
|
}
|
||||||
@@ -67,8 +81,11 @@ impl Form {
|
|||||||
impl Render for Form {
|
impl Render for Form {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
div()
|
div()
|
||||||
.h_12()
|
|
||||||
.flex_shrink_0()
|
.flex_shrink_0()
|
||||||
|
.w_full()
|
||||||
|
.h_12()
|
||||||
|
.border_t_1()
|
||||||
|
.border_color(cx.theme().border.opacity(0.7))
|
||||||
.flex()
|
.flex()
|
||||||
.items_center()
|
.items_center()
|
||||||
.gap_2()
|
.gap_2()
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use gpui::*;
|
use gpui::*;
|
||||||
use nostr_sdk::prelude::*;
|
use nostr_sdk::prelude::*;
|
||||||
|
use prelude::FluentBuilder;
|
||||||
|
|
||||||
use crate::get_client;
|
use crate::{get_client, states::chat::ChatRegistry};
|
||||||
|
|
||||||
pub struct MessageList {
|
pub struct MessageList {
|
||||||
member: PublicKey,
|
member: PublicKey,
|
||||||
@@ -56,28 +57,38 @@ impl MessageList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn subscribe(&self, cx: &mut ViewContext<Self>) {
|
pub fn subscribe(&self, cx: &mut ViewContext<Self>) {
|
||||||
/*
|
let messages = self.messages.clone();
|
||||||
let receiver = cx.global::<ChatRegistry>().receiver.clone();
|
|
||||||
|
|
||||||
cx.foreground_executor()
|
cx.observe_global::<ChatRegistry>(move |_, cx| {
|
||||||
.spawn(async move {
|
let state = cx.global::<ChatRegistry>();
|
||||||
while let Ok(event) = receiver.recv_async().await {
|
let events = state.new_messages.clone();
|
||||||
println!("New message: {}", event.as_json())
|
|
||||||
|
cx.update_model(&messages, |a, b| {
|
||||||
|
if let Some(m) = a {
|
||||||
|
m.extend(events);
|
||||||
|
b.notify();
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
.detach();
|
})
|
||||||
*/
|
.detach();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Render for MessageList {
|
impl Render for MessageList {
|
||||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||||
let mut content = div().size_full().flex().flex_col().justify_end();
|
div()
|
||||||
|
.h_full()
|
||||||
if let Some(messages) = self.messages.read(cx).as_ref() {
|
.flex()
|
||||||
content = content.children(messages.clone().into_iter().map(|m| div().child(m.content)))
|
.flex_col_reverse()
|
||||||
}
|
.justify_end()
|
||||||
|
.when_some(self.messages.read(cx).as_ref(), |this, messages| {
|
||||||
div().flex_1().child(content)
|
this.children(messages.clone().into_iter().map(|m| {
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.child(m.pubkey.to_hex())
|
||||||
|
.child(m.content)
|
||||||
|
}))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use coop_ui::{
|
|||||||
button::Button,
|
button::Button,
|
||||||
dock::{Panel, PanelEvent, PanelState, TitleStyle},
|
dock::{Panel, PanelEvent, PanelState, TitleStyle},
|
||||||
popup_menu::PopupMenu,
|
popup_menu::PopupMenu,
|
||||||
|
v_flex,
|
||||||
};
|
};
|
||||||
use form::Form;
|
use form::Form;
|
||||||
use gpui::*;
|
use gpui::*;
|
||||||
@@ -90,11 +91,9 @@ impl FocusableView for ChatPanel {
|
|||||||
|
|
||||||
impl Render for ChatPanel {
|
impl Render for ChatPanel {
|
||||||
fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> impl IntoElement {
|
fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> impl IntoElement {
|
||||||
div()
|
v_flex()
|
||||||
.size_full()
|
.size_full()
|
||||||
.flex()
|
.child(div().flex_1().min_h_0().child(self.list.clone()))
|
||||||
.flex_col()
|
|
||||||
.child(self.list.clone())
|
|
||||||
.child(self.form.clone())
|
.child(self.form.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
use gpui::{
|
||||||
|
div, prelude::FluentBuilder as _, px, relative, AnyElement, ClickEvent, Corners, Div, Edges,
|
||||||
|
ElementId, Hsla, InteractiveElement, IntoElement, MouseButton, ParentElement, Pixels,
|
||||||
|
RenderOnce, SharedString, StatefulInteractiveElement as _, Styled, WindowContext,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
h_flex,
|
h_flex,
|
||||||
indicator::Indicator,
|
indicator::Indicator,
|
||||||
@@ -5,11 +11,6 @@ use crate::{
|
|||||||
tooltip::Tooltip,
|
tooltip::Tooltip,
|
||||||
Disableable, Icon, Selectable, Sizable, Size,
|
Disableable, Icon, Selectable, Sizable, Size,
|
||||||
};
|
};
|
||||||
use gpui::{
|
|
||||||
div, prelude::FluentBuilder as _, px, relative, AnyElement, ClickEvent, Corners, Div, Edges,
|
|
||||||
ElementId, Hsla, InteractiveElement, IntoElement, MouseButton, ParentElement, Pixels,
|
|
||||||
RenderOnce, SharedString, StatefulInteractiveElement as _, Styled, WindowContext,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub enum ButtonRounded {
|
pub enum ButtonRounded {
|
||||||
None,
|
None,
|
||||||
@@ -574,7 +575,8 @@ impl ButtonVariant {
|
|||||||
fn active(&self, cx: &WindowContext) -> ButtonVariantStyle {
|
fn active(&self, cx: &WindowContext) -> ButtonVariantStyle {
|
||||||
let bg = match self {
|
let bg = match self {
|
||||||
ButtonVariant::Primary => cx.theme().primary_active,
|
ButtonVariant::Primary => cx.theme().primary_active,
|
||||||
ButtonVariant::Secondary | ButtonVariant::Outline | ButtonVariant::Ghost => {
|
ButtonVariant::Secondary | ButtonVariant::Outline => cx.theme().secondary_active,
|
||||||
|
ButtonVariant::Ghost => {
|
||||||
if cx.theme().mode.is_dark() {
|
if cx.theme().mode.is_dark() {
|
||||||
cx.theme().secondary.lighten(0.2).opacity(0.8)
|
cx.theme().secondary.lighten(0.2).opacity(0.8)
|
||||||
} else {
|
} else {
|
||||||
@@ -607,7 +609,8 @@ impl ButtonVariant {
|
|||||||
fn selected(&self, cx: &WindowContext) -> ButtonVariantStyle {
|
fn selected(&self, cx: &WindowContext) -> ButtonVariantStyle {
|
||||||
let bg = match self {
|
let bg = match self {
|
||||||
ButtonVariant::Primary => cx.theme().primary_active,
|
ButtonVariant::Primary => cx.theme().primary_active,
|
||||||
ButtonVariant::Secondary | ButtonVariant::Outline | ButtonVariant::Ghost => {
|
ButtonVariant::Secondary | ButtonVariant::Outline => cx.theme().secondary_active,
|
||||||
|
ButtonVariant::Ghost => {
|
||||||
if cx.theme().mode.is_dark() {
|
if cx.theme().mode.is_dark() {
|
||||||
cx.theme().secondary.lighten(0.2).opacity(0.8)
|
cx.theme().secondary.lighten(0.2).opacity(0.8)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
use gpui::{
|
use gpui::{
|
||||||
anchored, canvas, deferred, div, prelude::FluentBuilder as _, px, relative, AnchorCorner,
|
anchored, canvas, deferred, div, prelude::FluentBuilder as _, px, relative, AppContext, Bounds,
|
||||||
AppContext, Bounds, ElementId, EventEmitter, FocusHandle, FocusableView, Hsla,
|
Corner, ElementId, EventEmitter, FocusHandle, FocusableView, Hsla, InteractiveElement as _,
|
||||||
InteractiveElement as _, IntoElement, KeyBinding, MouseButton, ParentElement, Pixels, Point,
|
IntoElement, KeyBinding, MouseButton, ParentElement, Pixels, Point, Render, SharedString,
|
||||||
Render, SharedString, StatefulInteractiveElement as _, Styled, View, ViewContext,
|
StatefulInteractiveElement as _, Styled, View, ViewContext, VisualContext,
|
||||||
VisualContext,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -63,7 +62,7 @@ pub struct ColorPicker {
|
|||||||
hovered_color: Option<Hsla>,
|
hovered_color: Option<Hsla>,
|
||||||
label: Option<SharedString>,
|
label: Option<SharedString>,
|
||||||
size: Size,
|
size: Size,
|
||||||
anchor: AnchorCorner,
|
anchor: Corner,
|
||||||
color_input: View<TextInput>,
|
color_input: View<TextInput>,
|
||||||
|
|
||||||
open: bool,
|
open: bool,
|
||||||
@@ -112,7 +111,7 @@ impl ColorPicker {
|
|||||||
hovered_color: None,
|
hovered_color: None,
|
||||||
size: Size::Medium,
|
size: Size::Medium,
|
||||||
label: None,
|
label: None,
|
||||||
anchor: AnchorCorner::TopLeft,
|
anchor: Corner::TopLeft,
|
||||||
color_input,
|
color_input,
|
||||||
open: false,
|
open: false,
|
||||||
bounds: Bounds::default(),
|
bounds: Bounds::default(),
|
||||||
@@ -149,8 +148,8 @@ impl ColorPicker {
|
|||||||
|
|
||||||
/// Set the anchor corner of the color picker.
|
/// Set the anchor corner of the color picker.
|
||||||
///
|
///
|
||||||
/// Default is `AnchorCorner::TopLeft`.
|
/// Default is `Corner::TopLeft`.
|
||||||
pub fn anchor(mut self, anchor: AnchorCorner) -> Self {
|
pub fn anchor(mut self, anchor: Corner) -> Self {
|
||||||
self.anchor = anchor;
|
self.anchor = anchor;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -262,13 +261,12 @@ impl ColorPicker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn resolved_corner(&self, bounds: Bounds<Pixels>) -> Point<Pixels> {
|
fn resolved_corner(&self, bounds: Bounds<Pixels>) -> Point<Pixels> {
|
||||||
match self.anchor {
|
bounds.corner(match self.anchor {
|
||||||
AnchorCorner::TopLeft => AnchorCorner::BottomLeft,
|
Corner::TopLeft => Corner::BottomLeft,
|
||||||
AnchorCorner::TopRight => AnchorCorner::BottomRight,
|
Corner::TopRight => Corner::BottomRight,
|
||||||
AnchorCorner::BottomLeft => AnchorCorner::TopLeft,
|
Corner::BottomLeft => Corner::TopLeft,
|
||||||
AnchorCorner::BottomRight => AnchorCorner::TopRight,
|
Corner::BottomRight => Corner::TopRight,
|
||||||
}
|
})
|
||||||
.corner(bounds)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,12 +345,8 @@ impl Render for ColorPicker {
|
|||||||
div()
|
div()
|
||||||
.occlude()
|
.occlude()
|
||||||
.map(|this| match self.anchor {
|
.map(|this| match self.anchor {
|
||||||
AnchorCorner::TopLeft | AnchorCorner::TopRight => {
|
Corner::TopLeft | Corner::TopRight => this.mt_1p5(),
|
||||||
this.mt_1p5()
|
Corner::BottomLeft | Corner::BottomRight => this.mb_1p5(),
|
||||||
}
|
|
||||||
AnchorCorner::BottomLeft | AnchorCorner::BottomRight => {
|
|
||||||
this.mb_1p5()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.w_72()
|
.w_72()
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use std::{cell::RefCell, rc::Rc};
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
anchored, deferred, div, prelude::FluentBuilder, px, relative, AnchorCorner, AnyElement,
|
anchored, deferred, div, prelude::FluentBuilder, px, relative, AnyElement, Corner,
|
||||||
DismissEvent, DispatchPhase, Element, ElementId, Focusable, GlobalElementId,
|
DismissEvent, DispatchPhase, Element, ElementId, Focusable, GlobalElementId,
|
||||||
InteractiveElement, IntoElement, MouseButton, MouseDownEvent, ParentElement, Pixels, Point,
|
InteractiveElement, IntoElement, MouseButton, MouseDownEvent, ParentElement, Pixels, Point,
|
||||||
Position, Stateful, Style, View, ViewContext, WindowContext,
|
Position, Stateful, Style, View, ViewContext, WindowContext,
|
||||||
@@ -27,7 +27,7 @@ type Menu<M> = Option<Box<dyn Fn(PopupMenu, &mut ViewContext<M>) -> PopupMenu +
|
|||||||
pub struct ContextMenu {
|
pub struct ContextMenu {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
menu: Menu<PopupMenu>,
|
menu: Menu<PopupMenu>,
|
||||||
anchor: AnchorCorner,
|
anchor: Corner,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextMenu {
|
impl ContextMenu {
|
||||||
@@ -35,7 +35,7 @@ impl ContextMenu {
|
|||||||
Self {
|
Self {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
menu: None,
|
menu: None,
|
||||||
anchor: AnchorCorner::TopLeft,
|
anchor: Corner::TopLeft,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use gpui::{
|
use gpui::{
|
||||||
div, prelude::FluentBuilder, px, rems, AnchorCorner, AppContext, DefiniteLength, DismissEvent,
|
div, prelude::FluentBuilder, px, rems, AppContext, Corner, DefiniteLength, DismissEvent,
|
||||||
DragMoveEvent, Empty, Entity, EventEmitter, FocusHandle, FocusableView,
|
DragMoveEvent, Empty, Entity, EventEmitter, FocusHandle, FocusableView,
|
||||||
InteractiveElement as _, IntoElement, ParentElement, Pixels, Render, ScrollHandle,
|
InteractiveElement as _, IntoElement, ParentElement, Pixels, Render, ScrollHandle,
|
||||||
SharedString, StatefulInteractiveElement, Styled, View, ViewContext, VisualContext as _,
|
SharedString, StatefulInteractiveElement, Styled, View, ViewContext, VisualContext as _,
|
||||||
@@ -367,7 +367,7 @@ impl TabPanel {
|
|||||||
this.separator().menu("Close", Box::new(ClosePanel))
|
this.separator().menu("Close", Box::new(ClosePanel))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.anchor(AnchorCorner::TopRight),
|
.anchor(Corner::TopRight),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ pub mod switch;
|
|||||||
pub mod tab;
|
pub mod tab;
|
||||||
pub mod theme;
|
pub mod theme;
|
||||||
pub mod tooltip;
|
pub mod tooltip;
|
||||||
|
pub mod virtual_list;
|
||||||
|
|
||||||
pub use crate::Disableable;
|
pub use crate::Disableable;
|
||||||
pub use event::InteractiveElementExt;
|
pub use event::InteractiveElementExt;
|
||||||
@@ -51,6 +52,7 @@ pub use focusable::FocusableCycle;
|
|||||||
pub use root::{ContextModal, Root};
|
pub use root::{ContextModal, Root};
|
||||||
pub use styled::*;
|
pub use styled::*;
|
||||||
pub use title_bar::*;
|
pub use title_bar::*;
|
||||||
|
pub use virtual_list::{h_virtual_list, v_virtual_list, VirtualList};
|
||||||
|
|
||||||
pub use colors::*;
|
pub use colors::*;
|
||||||
pub use icon::*;
|
pub use icon::*;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use gpui::{
|
use gpui::{
|
||||||
actions, anchored, deferred, div, prelude::FluentBuilder as _, px, AnchorCorner, AnyElement,
|
actions, anchored, deferred, div, prelude::FluentBuilder as _, px, AnyElement, AppContext,
|
||||||
AppContext, Bounds, DismissEvent, DispatchPhase, Element, ElementId, EventEmitter, FocusHandle,
|
Bounds, Corner, DismissEvent, DispatchPhase, Element, ElementId, EventEmitter, FocusHandle,
|
||||||
FocusableView, GlobalElementId, Hitbox, InteractiveElement as _, IntoElement, KeyBinding,
|
FocusableView, GlobalElementId, Hitbox, InteractiveElement as _, IntoElement, KeyBinding,
|
||||||
LayoutId, ManagedView, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, Render,
|
LayoutId, ManagedView, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, Render,
|
||||||
Style, StyleRefinement, Styled, View, ViewContext, VisualContext, WindowContext,
|
Style, StyleRefinement, Styled, View, ViewContext, VisualContext, WindowContext,
|
||||||
@@ -69,7 +69,7 @@ type ViewContent<M> = Option<Rc<dyn Fn(&mut WindowContext) -> View<M> + 'static>
|
|||||||
|
|
||||||
pub struct Popover<M: ManagedView> {
|
pub struct Popover<M: ManagedView> {
|
||||||
id: ElementId,
|
id: ElementId,
|
||||||
anchor: AnchorCorner,
|
anchor: Corner,
|
||||||
trigger: Trigger,
|
trigger: Trigger,
|
||||||
content: ViewContent<M>,
|
content: ViewContent<M>,
|
||||||
/// Style for trigger element.
|
/// Style for trigger element.
|
||||||
@@ -87,7 +87,7 @@ where
|
|||||||
pub fn new(id: impl Into<ElementId>) -> Self {
|
pub fn new(id: impl Into<ElementId>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
id: id.into(),
|
id: id.into(),
|
||||||
anchor: AnchorCorner::TopLeft,
|
anchor: Corner::TopLeft,
|
||||||
trigger: None,
|
trigger: None,
|
||||||
trigger_style: None,
|
trigger_style: None,
|
||||||
content: None,
|
content: None,
|
||||||
@@ -96,7 +96,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn anchor(mut self, anchor: AnchorCorner) -> Self {
|
pub fn anchor(mut self, anchor: Corner) -> Self {
|
||||||
self.anchor = anchor;
|
self.anchor = anchor;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@@ -153,13 +153,12 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn resolved_corner(&self, bounds: Bounds<Pixels>) -> Point<Pixels> {
|
fn resolved_corner(&self, bounds: Bounds<Pixels>) -> Point<Pixels> {
|
||||||
match self.anchor {
|
bounds.corner(match self.anchor {
|
||||||
AnchorCorner::TopLeft => AnchorCorner::BottomLeft,
|
Corner::TopLeft => Corner::BottomLeft,
|
||||||
AnchorCorner::TopRight => AnchorCorner::BottomRight,
|
Corner::TopRight => Corner::BottomRight,
|
||||||
AnchorCorner::BottomLeft => AnchorCorner::TopLeft,
|
Corner::BottomLeft => Corner::TopLeft,
|
||||||
AnchorCorner::BottomRight => AnchorCorner::TopRight,
|
Corner::BottomRight => Corner::TopRight,
|
||||||
}
|
})
|
||||||
.corner(bounds)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn with_element_state<R>(
|
fn with_element_state<R>(
|
||||||
@@ -273,12 +272,8 @@ impl<M: ManagedView> Element for Popover<M> {
|
|||||||
.occlude()
|
.occlude()
|
||||||
.when(!no_style, |this| this.popover_style(cx))
|
.when(!no_style, |this| this.popover_style(cx))
|
||||||
.map(|this| match anchor {
|
.map(|this| match anchor {
|
||||||
AnchorCorner::TopLeft | AnchorCorner::TopRight => {
|
Corner::TopLeft | Corner::TopRight => this.top_1p5(),
|
||||||
this.top_1p5()
|
Corner::BottomLeft | Corner::BottomRight => this.bottom_1p5(),
|
||||||
}
|
|
||||||
AnchorCorner::BottomLeft | AnchorCorner::BottomRight => {
|
|
||||||
this.bottom_1p5()
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.child(content_view.clone())
|
.child(content_view.clone())
|
||||||
.when(!no_style, |this| {
|
.when(!no_style, |this| {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use gpui::{
|
|||||||
SharedString, View, ViewContext, VisualContext as _, WindowContext,
|
SharedString, View, ViewContext, VisualContext as _, WindowContext,
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
anchored, canvas, rems, AnchorCorner, AnyElement, Bounds, Edges, FocusableView, Keystroke,
|
anchored, canvas, rems, AnyElement, Bounds, Corner, Edges, FocusableView, Keystroke,
|
||||||
ScrollHandle, StatefulInteractiveElement, Styled, WeakView,
|
ScrollHandle, StatefulInteractiveElement, Styled, WeakView,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -37,13 +37,13 @@ pub trait PopupMenuExt: Styled + Selectable + IntoElement + 'static {
|
|||||||
self,
|
self,
|
||||||
f: impl Fn(PopupMenu, &mut ViewContext<PopupMenu>) -> PopupMenu + 'static,
|
f: impl Fn(PopupMenu, &mut ViewContext<PopupMenu>) -> PopupMenu + 'static,
|
||||||
) -> Popover<PopupMenu> {
|
) -> Popover<PopupMenu> {
|
||||||
self.popup_menu_with_anchor(AnchorCorner::TopLeft, f)
|
self.popup_menu_with_anchor(Corner::TopLeft, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a popup menu with the given items, anchored to the given corner
|
/// Create a popup menu with the given items, anchored to the given corner
|
||||||
fn popup_menu_with_anchor(
|
fn popup_menu_with_anchor(
|
||||||
mut self,
|
mut self,
|
||||||
anchor: impl Into<AnchorCorner>,
|
anchor: impl Into<Corner>,
|
||||||
f: impl Fn(PopupMenu, &mut ViewContext<PopupMenu>) -> PopupMenu + 'static,
|
f: impl Fn(PopupMenu, &mut ViewContext<PopupMenu>) -> PopupMenu + 'static,
|
||||||
) -> Popover<PopupMenu> {
|
) -> Popover<PopupMenu> {
|
||||||
let style = self.style().clone();
|
let style = self.style().clone();
|
||||||
@@ -646,13 +646,10 @@ impl Render for PopupMenu {
|
|||||||
- bounds.origin.x
|
- bounds.origin.x
|
||||||
< max_width
|
< max_width
|
||||||
{
|
{
|
||||||
(
|
(Corner::TopRight, -px(15.))
|
||||||
AnchorCorner::TopRight,
|
|
||||||
-px(15.),
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
AnchorCorner::TopLeft,
|
Corner::TopLeft,
|
||||||
bounds.size.width
|
bounds.size.width
|
||||||
- px(10.),
|
- px(10.),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use std::{cell::Cell, rc::Rc};
|
|
||||||
|
|
||||||
use super::{Scrollbar, ScrollbarAxis, ScrollbarState};
|
|
||||||
use gpui::{
|
use gpui::{
|
||||||
canvas, div, relative, AnyElement, Div, Element, ElementId, EntityId, GlobalElementId,
|
canvas, div, relative, AnyElement, Div, Element, ElementId, EntityId, GlobalElementId,
|
||||||
InteractiveElement, IntoElement, ParentElement, Pixels, Position, ScrollHandle, SharedString,
|
InteractiveElement, IntoElement, ParentElement, Pixels, Position, ScrollHandle, SharedString,
|
||||||
Size, Stateful, StatefulInteractiveElement, Style, StyleRefinement, Styled, WindowContext,
|
Size, Stateful, StatefulInteractiveElement, Style, StyleRefinement, Styled, WindowContext,
|
||||||
};
|
};
|
||||||
|
use std::{cell::Cell, rc::Rc};
|
||||||
|
|
||||||
|
use super::{Scrollbar, ScrollbarAxis, ScrollbarState};
|
||||||
|
|
||||||
/// A scroll view is a container that allows the user to scroll through a large amount of content.
|
/// A scroll view is a container that allows the user to scroll through a large amount of content.
|
||||||
pub struct Scrollable<E> {
|
pub struct Scrollable<E> {
|
||||||
@@ -121,6 +121,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E> StatefulInteractiveElement for Scrollable<E> where E: Element + StatefulInteractiveElement {}
|
impl<E> StatefulInteractiveElement for Scrollable<E> where E: Element + StatefulInteractiveElement {}
|
||||||
|
|
||||||
impl<E> IntoElement for Scrollable<E>
|
impl<E> IntoElement for Scrollable<E>
|
||||||
@@ -202,8 +203,8 @@ where
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
.into_any_element();
|
.into_any_element();
|
||||||
let element_id = element.request_layout(cx);
|
|
||||||
|
|
||||||
|
let element_id = element.request_layout(cx);
|
||||||
let layout_id = cx.request_layout(style, vec![element_id]);
|
let layout_id = cx.request_layout(style, vec![element_id]);
|
||||||
|
|
||||||
(layout_id, element)
|
(layout_id, element)
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
|
use gpui::*;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{cell::Cell, rc::Rc, time::Instant};
|
use std::{cell::Cell, rc::Rc, time::Instant};
|
||||||
|
|
||||||
use crate::theme::ActiveTheme;
|
use crate::theme::ActiveTheme;
|
||||||
use gpui::{
|
|
||||||
fill, point, px, relative, AppContext, Bounds, ContentMask, CursorStyle, Edges, Element,
|
|
||||||
EntityId, Hitbox, Hsla, IntoElement, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad,
|
|
||||||
Pixels, Point, Position, ScrollHandle, ScrollWheelEvent, Style, UniformListScrollHandle,
|
|
||||||
};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
/// Scrollbar show mode.
|
/// Scrollbar show mode.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Hash, Default)]
|
||||||
@@ -22,6 +18,7 @@ impl ScrollbarShow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const BORDER_WIDTH: Pixels = px(0.);
|
||||||
const MIN_THUMB_SIZE: f32 = 80.;
|
const MIN_THUMB_SIZE: f32 = 80.;
|
||||||
const THUMB_RADIUS: Pixels = Pixels(3.0);
|
const THUMB_RADIUS: Pixels = Pixels(3.0);
|
||||||
const THUMB_INSET: Pixels = Pixels(4.);
|
const THUMB_INSET: Pixels = Pixels(4.);
|
||||||
@@ -357,11 +354,12 @@ pub struct AxisPrepaintState {
|
|||||||
axis: ScrollbarAxis,
|
axis: ScrollbarAxis,
|
||||||
bar_hitbox: Hitbox,
|
bar_hitbox: Hitbox,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
border_width: Pixels,
|
|
||||||
radius: Pixels,
|
radius: Pixels,
|
||||||
bg: Hsla,
|
bg: Hsla,
|
||||||
border: Hsla,
|
border: Hsla,
|
||||||
thumb_bounds: Bounds<Pixels>,
|
thumb_bounds: Bounds<Pixels>,
|
||||||
|
// Bounds of thumb to be rendered.
|
||||||
|
thumb_fill_bounds: Bounds<Pixels>,
|
||||||
thumb_bg: Hsla,
|
thumb_bg: Hsla,
|
||||||
scroll_size: Pixels,
|
scroll_size: Pixels,
|
||||||
container_size: Pixels,
|
container_size: Pixels,
|
||||||
@@ -387,7 +385,7 @@ impl Element for Scrollbar {
|
|||||||
position: Position::Absolute,
|
position: Position::Absolute,
|
||||||
flex_grow: 1.0,
|
flex_grow: 1.0,
|
||||||
flex_shrink: 1.0,
|
flex_shrink: 1.0,
|
||||||
size: gpui::Size {
|
size: Size {
|
||||||
width: relative(1.).into(),
|
width: relative(1.).into(),
|
||||||
height: relative(1.).into(),
|
height: relative(1.).into(),
|
||||||
},
|
},
|
||||||
@@ -517,11 +515,21 @@ impl Element for Scrollbar {
|
|||||||
idle_state
|
idle_state
|
||||||
};
|
};
|
||||||
|
|
||||||
let border_width = px(0.);
|
|
||||||
let thumb_bounds = if is_vertical {
|
let thumb_bounds = if is_vertical {
|
||||||
|
Bounds::from_corners(
|
||||||
|
point(bounds.origin.x, bounds.origin.y + thumb_start),
|
||||||
|
point(bounds.origin.x + self.width, bounds.origin.y + thumb_end),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Bounds::from_corners(
|
||||||
|
point(bounds.origin.x + thumb_start, bounds.origin.y),
|
||||||
|
point(bounds.origin.x + thumb_end, bounds.origin.y + self.width),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
let thumb_fill_bounds = if is_vertical {
|
||||||
Bounds::from_corners(
|
Bounds::from_corners(
|
||||||
point(
|
point(
|
||||||
bounds.origin.x + inset + border_width,
|
bounds.origin.x + inset + BORDER_WIDTH,
|
||||||
bounds.origin.y + thumb_start + inset,
|
bounds.origin.y + thumb_start + inset,
|
||||||
),
|
),
|
||||||
point(
|
point(
|
||||||
@@ -533,7 +541,7 @@ impl Element for Scrollbar {
|
|||||||
Bounds::from_corners(
|
Bounds::from_corners(
|
||||||
point(
|
point(
|
||||||
bounds.origin.x + thumb_start + inset,
|
bounds.origin.x + thumb_start + inset,
|
||||||
bounds.origin.y + inset + border_width,
|
bounds.origin.y + inset + BORDER_WIDTH,
|
||||||
),
|
),
|
||||||
point(
|
point(
|
||||||
bounds.origin.x + thumb_end - inset,
|
bounds.origin.x + thumb_end - inset,
|
||||||
@@ -550,11 +558,11 @@ impl Element for Scrollbar {
|
|||||||
axis,
|
axis,
|
||||||
bar_hitbox,
|
bar_hitbox,
|
||||||
bounds,
|
bounds,
|
||||||
border_width,
|
|
||||||
radius,
|
radius,
|
||||||
bg: bar_bg,
|
bg: bar_bg,
|
||||||
border: bar_border,
|
border: bar_border,
|
||||||
thumb_bounds,
|
thumb_bounds,
|
||||||
|
thumb_fill_bounds,
|
||||||
thumb_bg,
|
thumb_bg,
|
||||||
scroll_size: scroll_area_size,
|
scroll_size: scroll_area_size,
|
||||||
container_size,
|
container_size,
|
||||||
@@ -603,11 +611,11 @@ impl Element for Scrollbar {
|
|||||||
top: px(0.),
|
top: px(0.),
|
||||||
right: px(0.),
|
right: px(0.),
|
||||||
bottom: px(0.),
|
bottom: px(0.),
|
||||||
left: state.border_width,
|
left: BORDER_WIDTH,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Edges {
|
Edges {
|
||||||
top: state.border_width,
|
top: BORDER_WIDTH,
|
||||||
right: px(0.),
|
right: px(0.),
|
||||||
bottom: px(0.),
|
bottom: px(0.),
|
||||||
left: px(0.),
|
left: px(0.),
|
||||||
@@ -616,7 +624,7 @@ impl Element for Scrollbar {
|
|||||||
border_color: state.border,
|
border_color: state.border,
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.paint_quad(fill(thumb_bounds, state.thumb_bg).corner_radii(radius));
|
cx.paint_quad(fill(state.thumb_fill_bounds, state.thumb_bg).corner_radii(radius));
|
||||||
});
|
});
|
||||||
|
|
||||||
cx.on_mouse_event({
|
cx.on_mouse_event({
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ impl ThemeColor {
|
|||||||
scrollbar_thumb: hsl(0., 0., 69.).opacity(0.9),
|
scrollbar_thumb: hsl(0., 0., 69.).opacity(0.9),
|
||||||
scrollbar_thumb_hover: hsl(0., 0., 59.),
|
scrollbar_thumb_hover: hsl(0., 0., 59.),
|
||||||
secondary: hsl(240.0, 5.9, 96.9),
|
secondary: hsl(240.0, 5.9, 96.9),
|
||||||
secondary_active: hsl(240.0, 5.9, 93.),
|
secondary_active: hsl(240.0, 5.9, 90.),
|
||||||
secondary_foreground: hsl(240.0, 59.0, 10.),
|
secondary_foreground: hsl(240.0, 59.0, 10.),
|
||||||
secondary_hover: hsl(240.0, 5.9, 98.),
|
secondary_hover: hsl(240.0, 5.9, 98.),
|
||||||
selection: hsl(211.0, 97.0, 85.0),
|
selection: hsl(211.0, 97.0, 85.0),
|
||||||
|
|||||||
447
crates/ui/src/virtual_list.rs
Normal file
447
crates/ui/src/virtual_list.rs
Normal file
@@ -0,0 +1,447 @@
|
|||||||
|
//! Vistual List for render a large number of differently sized rows/columns.
|
||||||
|
//!
|
||||||
|
//! > NOTE: This must ensure each column width or row height.
|
||||||
|
//!
|
||||||
|
//! Only visible range are rendered for performance reasons.
|
||||||
|
//!
|
||||||
|
//! Inspired by `gpui::uniform_list`.
|
||||||
|
//! https://github.com/zed-industries/zed/blob/0ae1603610ab6b265bdfbee7b8dbc23c5ab06edc/crates/gpui/src/elements/uniform_list.rs
|
||||||
|
//!
|
||||||
|
//! Unlike the `uniform_list`, the each item can have different size.
|
||||||
|
//!
|
||||||
|
//! This is useful for more complex layout, for example, a table with different row height.
|
||||||
|
use std::{cmp, ops::Range, rc::Rc};
|
||||||
|
|
||||||
|
use gpui::{
|
||||||
|
div, point, px, size, AnyElement, AvailableSpace, Axis, Bounds, ContentMask, Div, Element,
|
||||||
|
ElementId, GlobalElementId, Hitbox, InteractiveElement, IntoElement, IsZero as _, Pixels,
|
||||||
|
Render, ScrollHandle, Size, Stateful, StatefulInteractiveElement, StyleRefinement, Styled,
|
||||||
|
View, ViewContext, WindowContext,
|
||||||
|
};
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
|
/// Create a virtual list in Vertical direction.
|
||||||
|
///
|
||||||
|
/// This is like `uniform_list` in GPUI, but support two axis.
|
||||||
|
///
|
||||||
|
/// The `item_sizes` is the size of each column.
|
||||||
|
pub fn v_virtual_list<R, V>(
|
||||||
|
view: View<V>,
|
||||||
|
id: impl Into<ElementId>,
|
||||||
|
item_sizes: Rc<Vec<Size<Pixels>>>,
|
||||||
|
f: impl 'static + Fn(&mut V, Range<usize>, Size<Pixels>, &mut ViewContext<V>) -> Vec<R>,
|
||||||
|
) -> VirtualList
|
||||||
|
where
|
||||||
|
R: IntoElement,
|
||||||
|
V: Render,
|
||||||
|
{
|
||||||
|
virtual_list(view, id, Axis::Vertical, item_sizes, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a virtual list in Horizontal direction.
|
||||||
|
pub fn h_virtual_list<R, V>(
|
||||||
|
view: View<V>,
|
||||||
|
id: impl Into<ElementId>,
|
||||||
|
item_sizes: Rc<Vec<Size<Pixels>>>,
|
||||||
|
f: impl 'static + Fn(&mut V, Range<usize>, Size<Pixels>, &mut ViewContext<V>) -> Vec<R>,
|
||||||
|
) -> VirtualList
|
||||||
|
where
|
||||||
|
R: IntoElement,
|
||||||
|
V: Render,
|
||||||
|
{
|
||||||
|
virtual_list(view, id, Axis::Horizontal, item_sizes, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn virtual_list<R, V>(
|
||||||
|
view: View<V>,
|
||||||
|
id: impl Into<ElementId>,
|
||||||
|
axis: Axis,
|
||||||
|
item_sizes: Rc<Vec<Size<Pixels>>>,
|
||||||
|
f: impl 'static + Fn(&mut V, Range<usize>, Size<Pixels>, &mut ViewContext<V>) -> Vec<R>,
|
||||||
|
) -> VirtualList
|
||||||
|
where
|
||||||
|
R: IntoElement,
|
||||||
|
V: Render,
|
||||||
|
{
|
||||||
|
let id: ElementId = id.into();
|
||||||
|
let scroll_handle = ScrollHandle::default();
|
||||||
|
let render_range = move |visible_range, content_size, cx: &mut WindowContext| {
|
||||||
|
view.update(cx, |this, cx| {
|
||||||
|
f(this, visible_range, content_size, cx)
|
||||||
|
.into_iter()
|
||||||
|
.map(|component| component.into_any_element())
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
VirtualList {
|
||||||
|
id: id.clone(),
|
||||||
|
axis,
|
||||||
|
base: div()
|
||||||
|
.id(id)
|
||||||
|
.size_full()
|
||||||
|
.overflow_scroll()
|
||||||
|
.track_scroll(&scroll_handle),
|
||||||
|
scroll_handle,
|
||||||
|
items_count: item_sizes.len(),
|
||||||
|
item_sizes,
|
||||||
|
render_items: Box::new(render_range),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type RenderItems = Box<
|
||||||
|
dyn for<'a> Fn(Range<usize>, Size<Pixels>, &'a mut WindowContext) -> SmallVec<[AnyElement; 64]>,
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// VirtualItem component for rendering a large number of differently sized columns.
|
||||||
|
pub struct VirtualList {
|
||||||
|
id: ElementId,
|
||||||
|
axis: Axis,
|
||||||
|
base: Stateful<Div>,
|
||||||
|
scroll_handle: ScrollHandle,
|
||||||
|
// scroll_handle: ScrollHandle,
|
||||||
|
items_count: usize,
|
||||||
|
item_sizes: Rc<Vec<Size<Pixels>>>,
|
||||||
|
render_items: RenderItems,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Styled for VirtualList {
|
||||||
|
fn style(&mut self) -> &mut StyleRefinement {
|
||||||
|
self.base.style()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VirtualList {
|
||||||
|
pub fn track_scroll(mut self, scroll_handle: &ScrollHandle) -> Self {
|
||||||
|
self.base = self.base.track_scroll(scroll_handle);
|
||||||
|
self.scroll_handle = scroll_handle.clone();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Specify for table
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub(crate) fn with_scroll_handle(mut self, scroll_handle: &ScrollHandle) -> Self {
|
||||||
|
self.base = div().id(self.id.clone()).size_full();
|
||||||
|
self.scroll_handle = scroll_handle.clone();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Measure first item to get the size.
|
||||||
|
fn measure_item(&self, cx: &mut WindowContext) -> Size<Pixels> {
|
||||||
|
if self.items_count == 0 {
|
||||||
|
return Size::default();
|
||||||
|
}
|
||||||
|
|
||||||
|
let item_ix = 0;
|
||||||
|
let mut items = (self.render_items)(item_ix..item_ix + 1, Size::default(), cx);
|
||||||
|
let Some(mut item_to_measure) = items.pop() else {
|
||||||
|
return Size::default();
|
||||||
|
};
|
||||||
|
let available_space = size(AvailableSpace::MinContent, AvailableSpace::MinContent);
|
||||||
|
item_to_measure.layout_as_root(available_space, cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Frame state used by the [VirtualItem].
|
||||||
|
pub struct VirtualListFrameState {
|
||||||
|
/// Visible items to be painted.
|
||||||
|
items: SmallVec<[AnyElement; 32]>,
|
||||||
|
item_sizes: Vec<Pixels>,
|
||||||
|
item_origins: Vec<Pixels>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoElement for VirtualList {
|
||||||
|
type Element = Self;
|
||||||
|
|
||||||
|
fn into_element(self) -> Self::Element {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Element for VirtualList {
|
||||||
|
type RequestLayoutState = VirtualListFrameState;
|
||||||
|
type PrepaintState = Option<Hitbox>;
|
||||||
|
|
||||||
|
fn id(&self) -> Option<ElementId> {
|
||||||
|
Some(self.id.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_layout(
|
||||||
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> (gpui::LayoutId, Self::RequestLayoutState) {
|
||||||
|
let style = self.base.interactivity().compute_style(global_id, None, cx);
|
||||||
|
let font_size = cx.text_style().font_size.to_pixels(cx.rem_size());
|
||||||
|
|
||||||
|
// Including the gap between items for calculate the item size
|
||||||
|
let gap = match self.axis {
|
||||||
|
Axis::Horizontal => style.gap.width,
|
||||||
|
Axis::Vertical => style.gap.height,
|
||||||
|
}
|
||||||
|
.to_pixels(font_size.into(), cx.rem_size());
|
||||||
|
|
||||||
|
// TODO: To cache the item_sizes, item_origins
|
||||||
|
// If there have 500,000 items, this method will speed about 500~600µs
|
||||||
|
// let start = std::time::Instant::now();
|
||||||
|
// Prepare each item's size by axis
|
||||||
|
let item_sizes = match self.axis {
|
||||||
|
Axis::Horizontal => self
|
||||||
|
.item_sizes
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, size)| {
|
||||||
|
if i == self.items_count - 1 {
|
||||||
|
size.width
|
||||||
|
} else {
|
||||||
|
size.width + gap
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
Axis::Vertical => self
|
||||||
|
.item_sizes
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(i, size)| {
|
||||||
|
if i == self.items_count - 1 {
|
||||||
|
size.height
|
||||||
|
} else {
|
||||||
|
size.height + gap
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Prepare each item's origin by axis
|
||||||
|
let item_origins = match self.axis {
|
||||||
|
Axis::Horizontal => item_sizes
|
||||||
|
.iter()
|
||||||
|
.scan(px(0.), |cumulative_x, size| {
|
||||||
|
let x = *cumulative_x;
|
||||||
|
*cumulative_x += *size;
|
||||||
|
Some(x)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
Axis::Vertical => item_sizes
|
||||||
|
.iter()
|
||||||
|
.scan(px(0.), |cumulative_y, size| {
|
||||||
|
let y = *cumulative_y;
|
||||||
|
*cumulative_y += *size;
|
||||||
|
Some(y)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>(),
|
||||||
|
};
|
||||||
|
// println!("layout: {} {:?}", item_sizes.len(), start.elapsed());
|
||||||
|
|
||||||
|
let (layout_id, _) = self.base.request_layout(global_id, cx);
|
||||||
|
|
||||||
|
(
|
||||||
|
layout_id,
|
||||||
|
VirtualListFrameState {
|
||||||
|
items: SmallVec::new(),
|
||||||
|
item_sizes,
|
||||||
|
item_origins,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prepaint(
|
||||||
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
layout: &mut Self::RequestLayoutState,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) -> Self::PrepaintState {
|
||||||
|
let style = self.base.interactivity().compute_style(global_id, None, cx);
|
||||||
|
let border = style.border_widths.to_pixels(cx.rem_size());
|
||||||
|
let padding = style.padding.to_pixels(bounds.size.into(), cx.rem_size());
|
||||||
|
|
||||||
|
let first_item_size = self.measure_item(cx);
|
||||||
|
|
||||||
|
let padded_bounds = Bounds::from_corners(
|
||||||
|
bounds.origin + point(border.left + padding.left, border.top + padding.top),
|
||||||
|
bounds.bottom_right()
|
||||||
|
- point(border.right + padding.right, border.bottom + padding.bottom),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Get border + padding pixel size
|
||||||
|
let padding_size = match self.axis {
|
||||||
|
Axis::Horizontal => border.left + padding.left + border.right + padding.right,
|
||||||
|
Axis::Vertical => border.top + padding.top + border.bottom + padding.bottom,
|
||||||
|
};
|
||||||
|
|
||||||
|
let item_sizes = &layout.item_sizes;
|
||||||
|
let item_origins = &layout.item_origins;
|
||||||
|
|
||||||
|
let content_size = match self.axis {
|
||||||
|
Axis::Horizontal => Size {
|
||||||
|
width: px(item_sizes.iter().map(|size| size.0).sum::<f32>()) + padding_size,
|
||||||
|
height: (first_item_size.height + padding_size).max(padded_bounds.size.height),
|
||||||
|
},
|
||||||
|
Axis::Vertical => Size {
|
||||||
|
width: (first_item_size.width + padding_size).max(padded_bounds.size.width),
|
||||||
|
height: px(item_sizes.iter().map(|size| size.0).sum::<f32>()) + padding_size,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
self.base.interactivity().prepaint(
|
||||||
|
global_id,
|
||||||
|
bounds,
|
||||||
|
content_size,
|
||||||
|
cx,
|
||||||
|
|style, _, hitbox, cx| {
|
||||||
|
let mut scroll_offset = self.scroll_handle.offset();
|
||||||
|
let border = style.border_widths.to_pixels(cx.rem_size());
|
||||||
|
let padding = style.padding.to_pixels(bounds.size.into(), cx.rem_size());
|
||||||
|
|
||||||
|
let padded_bounds = Bounds::from_corners(
|
||||||
|
bounds.origin + point(border.left + padding.left, border.top),
|
||||||
|
bounds.bottom_right() - point(border.right + padding.right, border.bottom),
|
||||||
|
);
|
||||||
|
|
||||||
|
if self.items_count > 0 {
|
||||||
|
let is_scrolled = match self.axis {
|
||||||
|
Axis::Horizontal => !scroll_offset.x.is_zero(),
|
||||||
|
Axis::Vertical => !scroll_offset.y.is_zero(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let min_scroll_offset = match self.axis {
|
||||||
|
Axis::Horizontal => padded_bounds.size.width - content_size.width,
|
||||||
|
Axis::Vertical => padded_bounds.size.height - content_size.height,
|
||||||
|
};
|
||||||
|
|
||||||
|
if is_scrolled {
|
||||||
|
match self.axis {
|
||||||
|
Axis::Horizontal if scroll_offset.x < min_scroll_offset => {
|
||||||
|
scroll_offset.x = min_scroll_offset;
|
||||||
|
}
|
||||||
|
Axis::Vertical if scroll_offset.y < min_scroll_offset => {
|
||||||
|
scroll_offset.y = min_scroll_offset;
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let (first_visible_element_ix, last_visible_element_ix) = match self.axis {
|
||||||
|
Axis::Horizontal => {
|
||||||
|
let mut cumulative_size = px(0.);
|
||||||
|
let mut first_visible_element_ix = 0;
|
||||||
|
for (i, &size) in item_sizes.iter().enumerate() {
|
||||||
|
cumulative_size += size;
|
||||||
|
if cumulative_size > -(scroll_offset.x + padding.left) {
|
||||||
|
first_visible_element_ix = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cumulative_size = px(0.);
|
||||||
|
let mut last_visible_element_ix = 0;
|
||||||
|
for (i, &size) in item_sizes.iter().enumerate() {
|
||||||
|
cumulative_size += size;
|
||||||
|
if cumulative_size > (-scroll_offset.x + padded_bounds.size.width) {
|
||||||
|
last_visible_element_ix = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if last_visible_element_ix == 0 {
|
||||||
|
last_visible_element_ix = self.items_count;
|
||||||
|
} else {
|
||||||
|
last_visible_element_ix += 1;
|
||||||
|
}
|
||||||
|
(first_visible_element_ix, last_visible_element_ix)
|
||||||
|
}
|
||||||
|
Axis::Vertical => {
|
||||||
|
let mut cumulative_size = px(0.);
|
||||||
|
let mut first_visible_element_ix = 0;
|
||||||
|
for (i, &size) in item_sizes.iter().enumerate() {
|
||||||
|
cumulative_size += size;
|
||||||
|
if cumulative_size > -(scroll_offset.y + padding.top) {
|
||||||
|
first_visible_element_ix = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cumulative_size = px(0.);
|
||||||
|
let mut last_visible_element_ix = 0;
|
||||||
|
for (i, &size) in item_sizes.iter().enumerate() {
|
||||||
|
cumulative_size += size;
|
||||||
|
if cumulative_size > (-scroll_offset.y + padded_bounds.size.height)
|
||||||
|
{
|
||||||
|
last_visible_element_ix = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if last_visible_element_ix == 0 {
|
||||||
|
last_visible_element_ix = self.items_count;
|
||||||
|
} else {
|
||||||
|
last_visible_element_ix += 1;
|
||||||
|
}
|
||||||
|
(first_visible_element_ix, last_visible_element_ix)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let visible_range = first_visible_element_ix
|
||||||
|
..cmp::min(last_visible_element_ix, self.items_count);
|
||||||
|
|
||||||
|
let items = (self.render_items)(visible_range.clone(), content_size, cx);
|
||||||
|
|
||||||
|
let content_mask = ContentMask { bounds };
|
||||||
|
cx.with_content_mask(Some(content_mask), |cx| {
|
||||||
|
for (mut item, ix) in items.into_iter().zip(visible_range.clone()) {
|
||||||
|
let item_origin = match self.axis {
|
||||||
|
Axis::Horizontal => {
|
||||||
|
padded_bounds.origin
|
||||||
|
+ point(
|
||||||
|
item_origins[ix] + scroll_offset.x,
|
||||||
|
padding.top + scroll_offset.y,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Axis::Vertical => {
|
||||||
|
padded_bounds.origin
|
||||||
|
+ point(
|
||||||
|
scroll_offset.x,
|
||||||
|
padding.top + item_origins[ix] + scroll_offset.y,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let available_space = match self.axis {
|
||||||
|
Axis::Horizontal => size(
|
||||||
|
AvailableSpace::Definite(item_sizes[ix]),
|
||||||
|
AvailableSpace::Definite(padded_bounds.size.height),
|
||||||
|
),
|
||||||
|
Axis::Vertical => size(
|
||||||
|
AvailableSpace::Definite(padded_bounds.size.width),
|
||||||
|
AvailableSpace::Definite(item_sizes[ix]),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
item.layout_as_root(available_space, cx);
|
||||||
|
item.prepaint_at(item_origin, cx);
|
||||||
|
layout.items.push(item);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
hitbox
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn paint(
|
||||||
|
&mut self,
|
||||||
|
global_id: Option<&GlobalElementId>,
|
||||||
|
bounds: Bounds<Pixels>,
|
||||||
|
layout: &mut Self::RequestLayoutState,
|
||||||
|
hitbox: &mut Self::PrepaintState,
|
||||||
|
cx: &mut WindowContext,
|
||||||
|
) {
|
||||||
|
self.base
|
||||||
|
.interactivity()
|
||||||
|
.paint(global_id, bounds, hitbox.as_ref(), cx, |_, cx| {
|
||||||
|
for item in &mut layout.items {
|
||||||
|
item.paint(cx);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user