Compare commits
40 Commits
add_subwor
...
remove-ext
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aac524858e | ||
|
|
6ef5d8f748 | ||
|
|
f912c545e7 | ||
|
|
ddc469ca3e | ||
|
|
e9bd4b2890 | ||
|
|
a119688a50 | ||
|
|
dcbff982ad | ||
|
|
ad51df7644 | ||
|
|
3f33ca01a8 | ||
|
|
5f4f3a9c87 | ||
|
|
344284e013 | ||
|
|
f6dabadaf7 | ||
|
|
ca6825066f | ||
|
|
a15360bcc8 | ||
|
|
016b5d60e1 | ||
|
|
9815358bdd | ||
|
|
ac60dcd67a | ||
|
|
3e3a5f04a2 | ||
|
|
7903f4ea58 | ||
|
|
a3dec643a1 | ||
|
|
02cc0b9afa | ||
|
|
787466383e | ||
|
|
34f8bb246a | ||
|
|
56b425fced | ||
|
|
ed61abb8b8 | ||
|
|
d71180abc2 | ||
|
|
af2ac1a4a0 | ||
|
|
c742cda8e8 | ||
|
|
52614482bf | ||
|
|
8b0a0dfb11 | ||
|
|
f5935d0cec | ||
|
|
d32fe0216f | ||
|
|
2957263b23 | ||
|
|
95911aaa14 | ||
|
|
1a9f0a647a | ||
|
|
45c714110e | ||
|
|
4c84600630 | ||
|
|
564936e1fe | ||
|
|
3d4e0780c4 | ||
|
|
44a46e3713 |
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
outputs:
|
||||
docs_only: ${{ steps.check_changes.outputs.docs_only }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Check for non-docs changes
|
||||
|
||||
364
Cargo.lock
generated
364
Cargo.lock
generated
@@ -258,9 +258,9 @@ checksum = "34cd60c5e3152cef0a592f1b296f1cc93715d89d2551d85315828c3a09575ff4"
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.94"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7"
|
||||
checksum = "34ac096ce696dc2fcabef30516bb13c0a68a11d30131d3df6f04711467681b04"
|
||||
|
||||
[[package]]
|
||||
name = "approx"
|
||||
@@ -388,7 +388,7 @@ dependencies = [
|
||||
"ctor",
|
||||
"db",
|
||||
"editor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"feature_flags",
|
||||
"fs",
|
||||
"futures 0.3.31",
|
||||
@@ -579,9 +579,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-broadcast"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "20cd0e2e25ea8e5f7e9df04578dc6cf5c83577fd09b1a46aaf5c85e1c33f2a7e"
|
||||
checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532"
|
||||
dependencies = [
|
||||
"event-listener 5.3.1",
|
||||
"event-listener-strategy",
|
||||
@@ -1805,16 +1805,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "blade-graphics"
|
||||
version = "0.5.0"
|
||||
source = "git+https://github.com/kvark/blade?rev=099555282605c7c4cca9e66a8f40148298347f80#099555282605c7c4cca9e66a8f40148298347f80"
|
||||
version = "0.6.0"
|
||||
source = "git+https://github.com/kvark/blade?rev=091a8401033847bb9b6ace3fcf70448d069621c5#091a8401033847bb9b6ace3fcf70448d069621c5"
|
||||
dependencies = [
|
||||
"ash",
|
||||
"ash-window",
|
||||
"bitflags 2.6.0",
|
||||
"block",
|
||||
"bytemuck",
|
||||
"codespan-reporting",
|
||||
"core-graphics-types 0.1.3",
|
||||
"glow",
|
||||
"gpu-alloc",
|
||||
"gpu-alloc-ash",
|
||||
@@ -1823,10 +1821,14 @@ dependencies = [
|
||||
"khronos-egl",
|
||||
"libloading",
|
||||
"log",
|
||||
"metal",
|
||||
"mint",
|
||||
"naga",
|
||||
"objc",
|
||||
"objc2",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation",
|
||||
"objc2-metal",
|
||||
"objc2-quartz-core",
|
||||
"objc2-ui-kit",
|
||||
"raw-window-handle",
|
||||
"slab",
|
||||
"wasm-bindgen",
|
||||
@@ -1836,7 +1838,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "blade-macros"
|
||||
version = "0.3.0"
|
||||
source = "git+https://github.com/kvark/blade?rev=099555282605c7c4cca9e66a8f40148298347f80#099555282605c7c4cca9e66a8f40148298347f80"
|
||||
source = "git+https://github.com/kvark/blade?rev=091a8401033847bb9b6ace3fcf70448d069621c5#091a8401033847bb9b6ace3fcf70448d069621c5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1845,8 +1847,8 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "blade-util"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/kvark/blade?rev=099555282605c7c4cca9e66a8f40148298347f80#099555282605c7c4cca9e66a8f40148298347f80"
|
||||
version = "0.2.0"
|
||||
source = "git+https://github.com/kvark/blade?rev=091a8401033847bb9b6ace3fcf70448d069621c5#091a8401033847bb9b6ace3fcf70448d069621c5"
|
||||
dependencies = [
|
||||
"blade-graphics",
|
||||
"bytemuck",
|
||||
@@ -1891,6 +1893,15 @@ dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block2"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f"
|
||||
dependencies = [
|
||||
"objc2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blocking"
|
||||
version = "1.6.1"
|
||||
@@ -1934,10 +1945,10 @@ dependencies = [
|
||||
"editor",
|
||||
"gpui",
|
||||
"itertools 0.13.0",
|
||||
"outline",
|
||||
"theme",
|
||||
"ui",
|
||||
"workspace",
|
||||
"zed_actions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2141,7 +2152,7 @@ dependencies = [
|
||||
"cap-primitives",
|
||||
"cap-std",
|
||||
"io-lifetimes 2.0.4",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2169,7 +2180,7 @@ dependencies = [
|
||||
"ipnet",
|
||||
"maybe-owned",
|
||||
"rustix 0.38.42",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
"winx",
|
||||
]
|
||||
|
||||
@@ -2484,7 +2495,6 @@ dependencies = [
|
||||
"exec",
|
||||
"fork",
|
||||
"ipc-channel",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"paths",
|
||||
"plist",
|
||||
@@ -2511,7 +2521,6 @@ dependencies = [
|
||||
"gpui",
|
||||
"http_client",
|
||||
"log",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"paths",
|
||||
"postage",
|
||||
@@ -2654,7 +2663,7 @@ dependencies = [
|
||||
"dashmap 6.1.0",
|
||||
"derive_more",
|
||||
"editor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"envy",
|
||||
"extension",
|
||||
"file_finder",
|
||||
@@ -2810,7 +2819,7 @@ dependencies = [
|
||||
"command_palette_hooks",
|
||||
"ctor",
|
||||
"editor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"fuzzy",
|
||||
"go_to_line",
|
||||
"gpui",
|
||||
@@ -2919,7 +2928,6 @@ dependencies = [
|
||||
"serde_json",
|
||||
"settings",
|
||||
"smol",
|
||||
"ui",
|
||||
"url",
|
||||
"util",
|
||||
"workspace",
|
||||
@@ -3681,7 +3689,7 @@ dependencies = [
|
||||
"collections",
|
||||
"ctor",
|
||||
"editor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"feature_flags",
|
||||
"gpui",
|
||||
"language",
|
||||
@@ -3886,7 +3894,7 @@ dependencies = [
|
||||
"ctor",
|
||||
"db",
|
||||
"emojis",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"feature_flags",
|
||||
"file_icons",
|
||||
"fs",
|
||||
@@ -4083,9 +4091,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.11.5"
|
||||
version = "0.11.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d"
|
||||
checksum = "dcaee3d8e3cfc3fd92428d477bc97fc29ec8716d180c0d74c643bb26166660e0"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -4137,7 +4145,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4189,7 +4197,7 @@ dependencies = [
|
||||
"client",
|
||||
"clock",
|
||||
"collections",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"feature_flags",
|
||||
"fs",
|
||||
"git",
|
||||
@@ -4305,7 +4313,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"clap",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"extension",
|
||||
"fs",
|
||||
"language",
|
||||
@@ -4333,7 +4341,7 @@ dependencies = [
|
||||
"collections",
|
||||
"context_server_settings",
|
||||
"ctor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"extension",
|
||||
"fs",
|
||||
"futures 0.3.31",
|
||||
@@ -4526,7 +4534,7 @@ dependencies = [
|
||||
"collections",
|
||||
"ctor",
|
||||
"editor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"file_icons",
|
||||
"futures 0.3.31",
|
||||
"fuzzy",
|
||||
@@ -4804,7 +4812,7 @@ checksum = "5e2e6123af26f0f2c51cc66869137080199406754903cc926a7690401ce09cb4"
|
||||
dependencies = [
|
||||
"io-lifetimes 2.0.4",
|
||||
"rustix 0.38.42",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5327,7 +5335,7 @@ dependencies = [
|
||||
"ctor",
|
||||
"derive_more",
|
||||
"embed-resource",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"etagere",
|
||||
"filedescriptor",
|
||||
"flume",
|
||||
@@ -5344,6 +5352,8 @@ dependencies = [
|
||||
"metal",
|
||||
"num_cpus",
|
||||
"objc",
|
||||
"objc2",
|
||||
"objc2-metal",
|
||||
"oo7",
|
||||
"open",
|
||||
"parking",
|
||||
@@ -6378,7 +6388,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2285ddfe3054097ef4b2fe909ef8c3bcd1ea52a8f0d274416caebeef39f04a65"
|
||||
dependencies = [
|
||||
"io-lifetimes 2.0.4",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -6681,7 +6691,7 @@ dependencies = [
|
||||
"collections",
|
||||
"ctor",
|
||||
"ec4rs",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"fs",
|
||||
"futures 0.3.31",
|
||||
"fuzzy",
|
||||
@@ -6848,7 +6858,7 @@ dependencies = [
|
||||
"collections",
|
||||
"copilot",
|
||||
"editor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"futures 0.3.31",
|
||||
"gpui",
|
||||
"itertools 0.13.0",
|
||||
@@ -6946,9 +6956,9 @@ checksum = "03087c2bad5e1034e8cace5926dec053fb3790248370865f5117a7d0213354c8"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.168"
|
||||
version = "0.2.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5aaeb2981e0606ca11d79718f8bb01164f1d6ed75080182d3abf017e6d244b6d"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
|
||||
[[package]]
|
||||
name = "libdbus-sys"
|
||||
@@ -6989,7 +6999,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.52.6",
|
||||
"windows-targets 0.48.5",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -7033,7 +7043,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "libwebrtc"
|
||||
version = "0.3.7"
|
||||
source = "git+https://github.com/zed-industries/rust-sdks?rev=799f10133d93ba2a88642cd480d01ec4da53408c#799f10133d93ba2a88642cd480d01ec4da53408c"
|
||||
source = "git+https://github.com/zed-industries/livekit-rust-sdks?rev=060964da10574cd9bf06463a53bf6e0769c5c45e#060964da10574cd9bf06463a53bf6e0769c5c45e"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"jni",
|
||||
@@ -7124,7 +7134,7 @@ checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104"
|
||||
[[package]]
|
||||
name = "livekit"
|
||||
version = "0.7.0"
|
||||
source = "git+https://github.com/zed-industries/rust-sdks?rev=799f10133d93ba2a88642cd480d01ec4da53408c#799f10133d93ba2a88642cd480d01ec4da53408c"
|
||||
source = "git+https://github.com/zed-industries/livekit-rust-sdks?rev=060964da10574cd9bf06463a53bf6e0769c5c45e#060964da10574cd9bf06463a53bf6e0769c5c45e"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"futures-util",
|
||||
@@ -7146,7 +7156,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "livekit-api"
|
||||
version = "0.4.1"
|
||||
source = "git+https://github.com/zed-industries/rust-sdks?rev=799f10133d93ba2a88642cd480d01ec4da53408c#799f10133d93ba2a88642cd480d01ec4da53408c"
|
||||
source = "git+https://github.com/zed-industries/livekit-rust-sdks?rev=060964da10574cd9bf06463a53bf6e0769c5c45e#060964da10574cd9bf06463a53bf6e0769c5c45e"
|
||||
dependencies = [
|
||||
"async-tungstenite 0.25.1",
|
||||
"futures-util",
|
||||
@@ -7171,7 +7181,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "livekit-protocol"
|
||||
version = "0.3.6"
|
||||
source = "git+https://github.com/zed-industries/rust-sdks?rev=799f10133d93ba2a88642cd480d01ec4da53408c#799f10133d93ba2a88642cd480d01ec4da53408c"
|
||||
source = "git+https://github.com/zed-industries/livekit-rust-sdks?rev=060964da10574cd9bf06463a53bf6e0769c5c45e#060964da10574cd9bf06463a53bf6e0769c5c45e"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"livekit-runtime",
|
||||
@@ -7188,7 +7198,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "livekit-runtime"
|
||||
version = "0.3.1"
|
||||
source = "git+https://github.com/zed-industries/rust-sdks?rev=799f10133d93ba2a88642cd480d01ec4da53408c#799f10133d93ba2a88642cd480d01ec4da53408c"
|
||||
source = "git+https://github.com/zed-industries/livekit-rust-sdks?rev=060964da10574cd9bf06463a53bf6e0769c5c45e#060964da10574cd9bf06463a53bf6e0769c5c45e"
|
||||
dependencies = [
|
||||
"async-io 2.4.0",
|
||||
"async-std",
|
||||
@@ -7321,7 +7331,7 @@ dependencies = [
|
||||
"async-pipe",
|
||||
"collections",
|
||||
"ctor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"futures 0.3.31",
|
||||
"gpui",
|
||||
"log",
|
||||
@@ -7384,7 +7394,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"assets",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"futures 0.3.31",
|
||||
"gpui",
|
||||
"language",
|
||||
@@ -7499,7 +7509,7 @@ dependencies = [
|
||||
"clap",
|
||||
"clap_complete",
|
||||
"elasticlunr-rs",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"futures-util",
|
||||
"handlebars 6.2.0",
|
||||
"ignore",
|
||||
@@ -7580,7 +7590,8 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "metal"
|
||||
version = "0.30.0"
|
||||
source = "git+https://github.com/gfx-rs/metal-rs?rev=ef768ff9d742ae6a0f4e83ddc8031264e7d460c4#ef768ff9d742ae6a0f4e83ddc8031264e7d460c4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c3572083504c43e14aec05447f8a3d57cce0f66d7a3c1b9058572eca4d70ab9"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block",
|
||||
@@ -7688,7 +7699,7 @@ dependencies = [
|
||||
"clock",
|
||||
"collections",
|
||||
"ctor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"futures 0.3.31",
|
||||
"gpui",
|
||||
"itertools 0.13.0",
|
||||
@@ -7720,8 +7731,9 @@ checksum = "defc4c55412d89136f966bbb339008b474350e5e6e78d2714439c386b3137a03"
|
||||
|
||||
[[package]]
|
||||
name = "naga"
|
||||
version = "23.0.0"
|
||||
source = "git+https://github.com/gfx-rs/wgpu?rev=1a643291c2e8854ba7e4f5445a4388202731bfa1#1a643291c2e8854ba7e4f5445a4388202731bfa1"
|
||||
version = "23.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "364f94bc34f61332abebe8cad6f6cd82a5b65cff22c828d05d0968911462ca4f"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bit-set 0.8.0",
|
||||
@@ -8151,6 +8163,208 @@ dependencies = [
|
||||
"malloc_buf",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc-sys"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310"
|
||||
|
||||
[[package]]
|
||||
name = "objc2"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804"
|
||||
dependencies = [
|
||||
"objc-sys",
|
||||
"objc2-encode",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-app-kit"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block2",
|
||||
"libc",
|
||||
"objc2",
|
||||
"objc2-core-data",
|
||||
"objc2-core-image",
|
||||
"objc2-foundation",
|
||||
"objc2-quartz-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-cloud-kit"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block2",
|
||||
"objc2",
|
||||
"objc2-core-location",
|
||||
"objc2-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-contacts"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
|
||||
dependencies = [
|
||||
"block2",
|
||||
"objc2",
|
||||
"objc2-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-data"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block2",
|
||||
"objc2",
|
||||
"objc2-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-image"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80"
|
||||
dependencies = [
|
||||
"block2",
|
||||
"objc2",
|
||||
"objc2-foundation",
|
||||
"objc2-metal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-core-location"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781"
|
||||
dependencies = [
|
||||
"block2",
|
||||
"objc2",
|
||||
"objc2-contacts",
|
||||
"objc2-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-encode"
|
||||
version = "4.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7891e71393cd1f227313c9379a26a584ff3d7e6e7159e988851f0934c993f0f8"
|
||||
|
||||
[[package]]
|
||||
name = "objc2-foundation"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block2",
|
||||
"libc",
|
||||
"objc2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-link-presentation"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
|
||||
dependencies = [
|
||||
"block2",
|
||||
"objc2",
|
||||
"objc2-app-kit",
|
||||
"objc2-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-metal"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block2",
|
||||
"objc2",
|
||||
"objc2-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-quartz-core"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block2",
|
||||
"objc2",
|
||||
"objc2-foundation",
|
||||
"objc2-metal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-symbols"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc"
|
||||
dependencies = [
|
||||
"objc2",
|
||||
"objc2-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-ui-kit"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block2",
|
||||
"objc2",
|
||||
"objc2-cloud-kit",
|
||||
"objc2-core-data",
|
||||
"objc2-core-image",
|
||||
"objc2-core-location",
|
||||
"objc2-foundation",
|
||||
"objc2-link-presentation",
|
||||
"objc2-quartz-core",
|
||||
"objc2-symbols",
|
||||
"objc2-uniform-type-identifiers",
|
||||
"objc2-user-notifications",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-uniform-type-identifiers"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
|
||||
dependencies = [
|
||||
"block2",
|
||||
"objc2",
|
||||
"objc2-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "objc2-user-notifications"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"block2",
|
||||
"objc2",
|
||||
"objc2-core-location",
|
||||
"objc2-foundation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.36.5"
|
||||
@@ -8415,6 +8629,7 @@ dependencies = [
|
||||
"ui",
|
||||
"util",
|
||||
"workspace",
|
||||
"zed_actions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -9194,7 +9409,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"ctor",
|
||||
"editor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"gpui",
|
||||
"menu",
|
||||
"serde",
|
||||
@@ -9551,7 +9766,7 @@ dependencies = [
|
||||
"client",
|
||||
"clock",
|
||||
"collections",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"fancy-regex 0.14.0",
|
||||
"fs",
|
||||
"futures 0.3.31",
|
||||
@@ -9933,7 +10148,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"socket2 0.5.8",
|
||||
"tracing",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10266,7 +10481,6 @@ name = "release_channel"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"gpui",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -10308,7 +10522,7 @@ dependencies = [
|
||||
"clap",
|
||||
"client",
|
||||
"clock",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"extension",
|
||||
"extension_host",
|
||||
"fork",
|
||||
@@ -10367,7 +10581,7 @@ dependencies = [
|
||||
"collections",
|
||||
"command_palette_hooks",
|
||||
"editor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"feature_flags",
|
||||
"file_icons",
|
||||
"futures 0.3.31",
|
||||
@@ -10642,7 +10856,7 @@ dependencies = [
|
||||
"arrayvec",
|
||||
"criterion",
|
||||
"ctor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"gpui",
|
||||
"log",
|
||||
"rand 0.8.5",
|
||||
@@ -10668,7 +10882,7 @@ dependencies = [
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
"collections",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"futures 0.3.31",
|
||||
"gpui",
|
||||
"parking_lot",
|
||||
@@ -10834,7 +11048,7 @@ dependencies = [
|
||||
"libc",
|
||||
"linux-raw-sys 0.4.14",
|
||||
"once_cell",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -11252,7 +11466,7 @@ dependencies = [
|
||||
"client",
|
||||
"clock",
|
||||
"collections",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"feature_flags",
|
||||
"fs",
|
||||
"futures 0.3.31",
|
||||
@@ -12254,7 +12468,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"ctor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"log",
|
||||
"rand 0.8.5",
|
||||
"rayon",
|
||||
@@ -12268,7 +12482,7 @@ dependencies = [
|
||||
"client",
|
||||
"collections",
|
||||
"editor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"futures 0.3.31",
|
||||
"gpui",
|
||||
"http_client",
|
||||
@@ -12554,7 +12768,7 @@ dependencies = [
|
||||
"fd-lock",
|
||||
"io-lifetimes 2.0.4",
|
||||
"rustix 0.38.42",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
"winx",
|
||||
]
|
||||
|
||||
@@ -12566,7 +12780,7 @@ dependencies = [
|
||||
"collections",
|
||||
"ctor",
|
||||
"editor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"gpui",
|
||||
"language",
|
||||
"menu",
|
||||
@@ -12686,7 +12900,7 @@ dependencies = [
|
||||
"fastrand 2.3.0",
|
||||
"once_cell",
|
||||
"rustix 0.38.42",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -12787,7 +13001,7 @@ dependencies = [
|
||||
"clock",
|
||||
"collections",
|
||||
"ctor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"gpui",
|
||||
"http_client",
|
||||
"log",
|
||||
@@ -14837,7 +15051,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "webrtc-sys"
|
||||
version = "0.3.5"
|
||||
source = "git+https://github.com/zed-industries/rust-sdks?rev=799f10133d93ba2a88642cd480d01ec4da53408c#799f10133d93ba2a88642cd480d01ec4da53408c"
|
||||
source = "git+https://github.com/zed-industries/livekit-rust-sdks?rev=060964da10574cd9bf06463a53bf6e0769c5c45e#060964da10574cd9bf06463a53bf6e0769c5c45e"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxx",
|
||||
@@ -14850,7 +15064,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "webrtc-sys-build"
|
||||
version = "0.3.5"
|
||||
source = "git+https://github.com/zed-industries/rust-sdks?rev=799f10133d93ba2a88642cd480d01ec4da53408c#799f10133d93ba2a88642cd480d01ec4da53408c"
|
||||
source = "git+https://github.com/zed-industries/livekit-rust-sdks?rev=060964da10574cd9bf06463a53bf6e0769c5c45e#060964da10574cd9bf06463a53bf6e0769c5c45e"
|
||||
dependencies = [
|
||||
"fs2",
|
||||
"regex",
|
||||
@@ -14989,7 +15203,7 @@ version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
|
||||
dependencies = [
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -15438,7 +15652,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f3fd376f71958b862e7afb20cfe5a22830e1963462f3a17f49d82a6c1d1f42d"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"windows-sys 0.59.0",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -15586,7 +15800,7 @@ dependencies = [
|
||||
"collections",
|
||||
"db",
|
||||
"derive_more",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"fs",
|
||||
"futures 0.3.31",
|
||||
"gpui",
|
||||
@@ -15622,7 +15836,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"clock",
|
||||
"collections",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"fs",
|
||||
"futures 0.3.31",
|
||||
"fuzzy",
|
||||
@@ -16019,7 +16233,7 @@ dependencies = [
|
||||
"db",
|
||||
"diagnostics",
|
||||
"editor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"extension",
|
||||
"extension_host",
|
||||
"extensions_ui",
|
||||
@@ -16445,7 +16659,7 @@ dependencies = [
|
||||
"collections",
|
||||
"ctor",
|
||||
"editor",
|
||||
"env_logger 0.11.5",
|
||||
"env_logger 0.11.6",
|
||||
"futures 0.3.31",
|
||||
"gpui",
|
||||
"http_client",
|
||||
|
||||
16
Cargo.toml
16
Cargo.toml
@@ -355,9 +355,9 @@ async-watch = "0.3.1"
|
||||
async_zip = { version = "0.0.17", features = ["deflate", "deflate64"] }
|
||||
base64 = "0.22"
|
||||
bitflags = "2.6.0"
|
||||
blade-graphics = { git = "https://github.com/kvark/blade", rev = "099555282605c7c4cca9e66a8f40148298347f80" }
|
||||
blade-macros = { git = "https://github.com/kvark/blade", rev = "099555282605c7c4cca9e66a8f40148298347f80" }
|
||||
blade-util = { git = "https://github.com/kvark/blade", rev = "099555282605c7c4cca9e66a8f40148298347f80" }
|
||||
blade-graphics = { git = "https://github.com/kvark/blade", rev = "091a8401033847bb9b6ace3fcf70448d069621c5" }
|
||||
blade-macros = { git = "https://github.com/kvark/blade", rev = "091a8401033847bb9b6ace3fcf70448d069621c5" }
|
||||
blade-util = { git = "https://github.com/kvark/blade", rev = "091a8401033847bb9b6ace3fcf70448d069621c5" }
|
||||
blake3 = "1.5.3"
|
||||
bytes = "1.0"
|
||||
cargo_metadata = "0.19"
|
||||
@@ -401,14 +401,13 @@ jupyter-websocket-client = { version = "0.8.0" }
|
||||
libc = "0.2"
|
||||
libsqlite3-sys = { version = "0.30.1", features = ["bundled"] }
|
||||
linkify = "0.10.0"
|
||||
livekit = { git = "https://github.com/zed-industries/rust-sdks", rev="799f10133d93ba2a88642cd480d01ec4da53408c", features = ["dispatcher", "services-dispatcher", "rustls-tls-native-roots"], default-features = false }
|
||||
livekit = { git = "https://github.com/zed-industries/livekit-rust-sdks", rev="060964da10574cd9bf06463a53bf6e0769c5c45e", features = ["dispatcher", "services-dispatcher", "rustls-tls-native-roots"], default-features = false }
|
||||
log = { version = "0.4.16", features = ["kv_unstable_serde", "serde"] }
|
||||
markup5ever_rcdom = "0.3.0"
|
||||
nanoid = "0.4"
|
||||
nbformat = { version = "0.9.0" }
|
||||
nix = "0.29"
|
||||
num-format = "0.4.4"
|
||||
once_cell = "1.19.0"
|
||||
ordered-float = "2.1.1"
|
||||
palette = { version = "0.7.5", default-features = false, features = ["std"] }
|
||||
parking_lot = "0.12.1"
|
||||
@@ -525,12 +524,7 @@ wasmtime-wasi = "24"
|
||||
which = "6.0.0"
|
||||
wit-component = "0.201"
|
||||
zstd = "0.11"
|
||||
# Custom metal-rs is only needed for "macos-blade" feature of GPUI
|
||||
#TODO: switch to crates once these are published:
|
||||
# - https://github.com/gfx-rs/metal-rs/pull/335
|
||||
# - https://github.com/gfx-rs/metal-rs/pull/336
|
||||
# - https://github.com/gfx-rs/metal-rs/pull/337
|
||||
metal = { git = "https://github.com/gfx-rs/metal-rs", rev = "ef768ff9d742ae6a0f4e83ddc8031264e7d460c4" }
|
||||
metal = "0.30"
|
||||
|
||||
[workspace.dependencies.async-stripe]
|
||||
git = "https://github.com/zed-industries/async-stripe"
|
||||
|
||||
@@ -260,6 +260,8 @@
|
||||
"ctrl-f4": "pane::CloseActiveItem",
|
||||
"alt-ctrl-t": ["pane::CloseInactiveItems", { "close_pinned": false }],
|
||||
"alt-ctrl-shift-w": "workspace::CloseInactiveTabsAndPanes",
|
||||
"ctrl-k e": ["pane::CloseItemsToTheLeft", { "close_pinned": false }],
|
||||
"ctrl-k t": ["pane::CloseItemsToTheRight", { "close_pinned": false }],
|
||||
"ctrl-k u": ["pane::CloseCleanItems", { "close_pinned": false }],
|
||||
"ctrl-k w": ["pane::CloseAllItems", { "close_pinned": false }],
|
||||
"ctrl-shift-f": "project_search::ToggleFocus",
|
||||
|
||||
@@ -327,6 +327,8 @@
|
||||
"cmd-w": "pane::CloseActiveItem",
|
||||
"alt-cmd-t": ["pane::CloseInactiveItems", { "close_pinned": false }],
|
||||
"ctrl-alt-cmd-w": "workspace::CloseInactiveTabsAndPanes",
|
||||
"cmd-k e": ["pane::CloseItemsToTheLeft", { "close_pinned": false }],
|
||||
"cmd-k t": ["pane::CloseItemsToTheRight", { "close_pinned": false }],
|
||||
"cmd-k u": ["pane::CloseCleanItems", { "close_pinned": false }],
|
||||
"cmd-k cmd-w": ["pane::CloseAllItems", { "close_pinned": false }],
|
||||
"cmd-f": "project_search::ToggleFocus",
|
||||
|
||||
@@ -389,9 +389,6 @@
|
||||
"bindings": {
|
||||
"w": "vim::Word",
|
||||
"shift-w": ["vim::Word", { "ignorePunctuation": true }],
|
||||
// Subword TextObject
|
||||
// "w": "vim::Subword",
|
||||
// "shift-w": ["vim::Subword", { "ignorePunctuation": true }],
|
||||
"t": "vim::Tag",
|
||||
"s": "vim::Sentence",
|
||||
"p": "vim::Paragraph",
|
||||
|
||||
@@ -1103,6 +1103,9 @@
|
||||
"prettier": {
|
||||
"allowed": true
|
||||
}
|
||||
},
|
||||
"Zig": {
|
||||
"language_servers": ["zls", "..."]
|
||||
}
|
||||
},
|
||||
// Different settings for specific language models.
|
||||
|
||||
@@ -1458,6 +1458,10 @@ impl Panel for AssistantPanel {
|
||||
fn toggle_action(&self) -> Box<dyn Action> {
|
||||
Box::new(ToggleFocus)
|
||||
}
|
||||
|
||||
fn activation_priority(&self) -> u32 {
|
||||
4
|
||||
}
|
||||
}
|
||||
|
||||
impl EventEmitter<PanelEvent> for AssistantPanel {}
|
||||
@@ -4966,8 +4970,8 @@ fn fold_toggle(
|
||||
) -> impl Fn(
|
||||
MultiBufferRow,
|
||||
bool,
|
||||
Arc<dyn Fn(bool, &mut WindowContext<'_>) + Send + Sync>,
|
||||
&mut WindowContext<'_>,
|
||||
Arc<dyn Fn(bool, &mut WindowContext) + Send + Sync>,
|
||||
&mut WindowContext,
|
||||
) -> AnyElement {
|
||||
move |row, is_folded, fold, _cx| {
|
||||
Disclosure::new((name, row.0 as u64), !is_folded)
|
||||
|
||||
@@ -149,6 +149,7 @@ impl SlashCommandCompletionProvider {
|
||||
server_id: LanguageServerId(0),
|
||||
lsp_completion: Default::default(),
|
||||
confirm,
|
||||
resolved: true,
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
@@ -242,6 +243,7 @@ impl SlashCommandCompletionProvider {
|
||||
server_id: LanguageServerId(0),
|
||||
lsp_completion: Default::default(),
|
||||
confirm,
|
||||
resolved: true,
|
||||
}
|
||||
})
|
||||
.collect())
|
||||
@@ -330,16 +332,6 @@ impl CompletionProvider for SlashCommandCompletionProvider {
|
||||
Task::ready(Ok(true))
|
||||
}
|
||||
|
||||
fn apply_additional_edits_for_completion(
|
||||
&self,
|
||||
_: Model<Buffer>,
|
||||
_: project::Completion,
|
||||
_: bool,
|
||||
_: &mut ViewContext<Editor>,
|
||||
) -> Task<Result<Option<language::Transaction>>> {
|
||||
Task::ready(Ok(None))
|
||||
}
|
||||
|
||||
fn is_completion_trigger(
|
||||
&self,
|
||||
buffer: &Model<Buffer>,
|
||||
|
||||
@@ -5,7 +5,7 @@ use assistant_slash_command::{
|
||||
};
|
||||
use feature_flags::FeatureFlag;
|
||||
use futures::StreamExt;
|
||||
use gpui::{AppContext, AsyncAppContext, Task, WeakView};
|
||||
use gpui::{AppContext, AsyncAppContext, AsyncWindowContext, Task, WeakView, WindowContext};
|
||||
use language::{CodeLabel, LspAdapterDelegate};
|
||||
use language_model::{
|
||||
LanguageModelCompletionEvent, LanguageModelRegistry, LanguageModelRequest,
|
||||
@@ -14,7 +14,7 @@ use language_model::{
|
||||
use semantic_index::{FileSummary, SemanticDb};
|
||||
use smol::channel;
|
||||
use std::sync::{atomic::AtomicBool, Arc};
|
||||
use ui::{prelude::*, BorrowAppContext, WindowContext};
|
||||
use ui::{prelude::*, BorrowAppContext};
|
||||
use util::ResultExt;
|
||||
use workspace::Workspace;
|
||||
|
||||
@@ -115,7 +115,7 @@ impl SlashCommand for AutoCommand {
|
||||
return Task::ready(Err(anyhow!("no project indexer")));
|
||||
};
|
||||
|
||||
let task = cx.spawn(|cx: gpui::AsyncWindowContext| async move {
|
||||
let task = cx.spawn(|cx: AsyncWindowContext| async move {
|
||||
let summaries = project_index
|
||||
.read_with(&cx, |project_index, cx| project_index.all_summaries(cx))?
|
||||
.await?;
|
||||
|
||||
@@ -281,7 +281,7 @@ fn tab_items_for_queries(
|
||||
|
||||
fn active_item_buffer(
|
||||
workspace: &mut Workspace,
|
||||
cx: &mut ui::ViewContext<Workspace>,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) -> anyhow::Result<BufferSnapshot> {
|
||||
let active_editor = workspace
|
||||
.active_item(cx)
|
||||
|
||||
@@ -27,8 +27,8 @@ enum SlashCommandEntry {
|
||||
Info(SlashCommandInfo),
|
||||
Advert {
|
||||
name: SharedString,
|
||||
renderer: fn(&mut WindowContext<'_>) -> AnyElement,
|
||||
on_confirm: fn(&mut WindowContext<'_>),
|
||||
renderer: fn(&mut WindowContext) -> AnyElement,
|
||||
on_confirm: fn(&mut WindowContext),
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ use std::sync::Arc;
|
||||
use assistant_tool::ToolWorkingSet;
|
||||
use collections::HashMap;
|
||||
use gpui::{
|
||||
list, AbsoluteLength, AnyElement, AppContext, CornersRefinement, DefiniteLength,
|
||||
EdgesRefinement, Empty, Length, ListAlignment, ListState, Model, StyleRefinement, Subscription,
|
||||
list, AbsoluteLength, AnyElement, AppContext, DefiniteLength, EdgesRefinement, Empty, Length,
|
||||
ListAlignment, ListOffset, ListState, Model, StyleRefinement, Subscription,
|
||||
TextStyleRefinement, View, WeakView,
|
||||
};
|
||||
use language::LanguageRegistry;
|
||||
@@ -108,7 +108,7 @@ impl ActiveThread {
|
||||
selection_background_color: cx.theme().players().local().selection,
|
||||
code_block: StyleRefinement {
|
||||
margin: EdgesRefinement {
|
||||
top: Some(Length::Definite(rems(0.5).into())),
|
||||
top: Some(Length::Definite(rems(1.0).into())),
|
||||
left: Some(Length::Definite(rems(0.).into())),
|
||||
right: Some(Length::Definite(rems(0.).into())),
|
||||
bottom: Some(Length::Definite(rems(1.).into())),
|
||||
@@ -120,19 +120,13 @@ impl ActiveThread {
|
||||
bottom: Some(DefiniteLength::Absolute(AbsoluteLength::Pixels(Pixels(8.)))),
|
||||
},
|
||||
background: Some(colors.editor_foreground.opacity(0.01).into()),
|
||||
border_color: Some(colors.border_variant.opacity(0.25)),
|
||||
border_color: Some(colors.border_variant.opacity(0.3)),
|
||||
border_widths: EdgesRefinement {
|
||||
top: Some(AbsoluteLength::Pixels(Pixels(1.0))),
|
||||
left: Some(AbsoluteLength::Pixels(Pixels(1.))),
|
||||
right: Some(AbsoluteLength::Pixels(Pixels(1.))),
|
||||
bottom: Some(AbsoluteLength::Pixels(Pixels(1.))),
|
||||
},
|
||||
corner_radii: CornersRefinement {
|
||||
top_left: Some(AbsoluteLength::Pixels(Pixels(2.))),
|
||||
top_right: Some(AbsoluteLength::Pixels(Pixels(2.))),
|
||||
bottom_right: Some(AbsoluteLength::Pixels(Pixels(2.))),
|
||||
bottom_left: Some(AbsoluteLength::Pixels(Pixels(2.))),
|
||||
},
|
||||
text: Some(TextStyleRefinement {
|
||||
font_family: Some(theme_settings.buffer_font.family.clone()),
|
||||
font_size: Some(buffer_font_size.into()),
|
||||
@@ -159,6 +153,10 @@ impl ActiveThread {
|
||||
)
|
||||
});
|
||||
self.rendered_messages_by_id.insert(*id, markdown);
|
||||
self.list_state.scroll_to(ListOffset {
|
||||
item_ix: old_len,
|
||||
offset_in_item: Pixels(0.0),
|
||||
});
|
||||
}
|
||||
|
||||
fn handle_thread_event(
|
||||
@@ -272,15 +270,20 @@ impl ActiveThread {
|
||||
),
|
||||
),
|
||||
)
|
||||
.child(v_flex().p_2p5().text_ui(cx).child(markdown.clone()))
|
||||
.child(div().p_2p5().text_ui(cx).child(markdown.clone()))
|
||||
.when_some(context, |parent, context| {
|
||||
parent.child(
|
||||
h_flex().flex_wrap().gap_1().p_1p5().children(
|
||||
context
|
||||
.iter()
|
||||
.map(|context| ContextPill::new(context.clone())),
|
||||
),
|
||||
)
|
||||
if !context.is_empty() {
|
||||
parent.child(
|
||||
h_flex()
|
||||
.flex_wrap()
|
||||
.gap_1()
|
||||
.px_1p5()
|
||||
.pb_1p5()
|
||||
.children(context.iter().map(|c| ContextPill::new(c.clone()))),
|
||||
)
|
||||
} else {
|
||||
parent
|
||||
}
|
||||
}),
|
||||
)
|
||||
.into_any()
|
||||
|
||||
@@ -286,6 +286,10 @@ impl Panel for AssistantPanel {
|
||||
fn toggle_action(&self) -> Box<dyn Action> {
|
||||
Box::new(ToggleFocus)
|
||||
}
|
||||
|
||||
fn activation_priority(&self) -> u32 {
|
||||
3
|
||||
}
|
||||
}
|
||||
|
||||
impl AssistantPanel {
|
||||
|
||||
@@ -21,7 +21,7 @@ pub struct Context {
|
||||
pub text: SharedString,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub enum ContextKind {
|
||||
File,
|
||||
Directory,
|
||||
|
||||
@@ -176,7 +176,7 @@ impl PickerDelegate for FetchContextPickerDelegate {
|
||||
|
||||
fn set_selected_index(&mut self, _ix: usize, _cx: &mut ViewContext<Picker<Self>>) {}
|
||||
|
||||
fn placeholder_text(&self, _cx: &mut ui::WindowContext) -> Arc<str> {
|
||||
fn placeholder_text(&self, _cx: &mut WindowContext) -> Arc<str> {
|
||||
"Enter a URL…".into()
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use crate::context_store::ContextStore;
|
||||
use crate::thread_store::ThreadStore;
|
||||
use crate::ui::ContextPill;
|
||||
use crate::ToggleContextPicker;
|
||||
use settings::Settings;
|
||||
|
||||
pub struct ContextStrip {
|
||||
context_store: Model<ContextStore>,
|
||||
@@ -45,7 +46,7 @@ impl ContextStrip {
|
||||
|
||||
impl Render for ContextStrip {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
let context = self.context_store.read(cx).context();
|
||||
let context = self.context_store.read(cx).context().clone();
|
||||
let context_picker = self.context_picker.clone();
|
||||
let focus_handle = self.focus_handle.clone();
|
||||
|
||||
@@ -76,6 +77,29 @@ impl Render for ContextStrip {
|
||||
})
|
||||
.with_handle(self.context_picker_menu_handle.clone()),
|
||||
)
|
||||
.when(context.is_empty(), {
|
||||
|parent| {
|
||||
parent.child(
|
||||
h_flex()
|
||||
.id("no-content-info")
|
||||
.ml_1p5()
|
||||
.gap_2()
|
||||
.font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
|
||||
.text_size(TextSize::Small.rems(cx))
|
||||
.text_color(cx.theme().colors().text_muted)
|
||||
.child("Add Context")
|
||||
.children(
|
||||
ui::KeyBinding::for_action_in(
|
||||
&ToggleContextPicker,
|
||||
&self.focus_handle,
|
||||
cx,
|
||||
)
|
||||
.map(|binding| binding.into_any_element()),
|
||||
)
|
||||
.opacity(0.5),
|
||||
)
|
||||
}
|
||||
})
|
||||
.children(context.iter().map(|context| {
|
||||
ContextPill::new(context.clone()).on_remove({
|
||||
let context = context.clone();
|
||||
@@ -88,19 +112,21 @@ impl Render for ContextStrip {
|
||||
}))
|
||||
})
|
||||
}))
|
||||
.when(!context.is_empty(), |parent| {
|
||||
parent.child(
|
||||
IconButton::new("remove-all-context", IconName::Eraser)
|
||||
.icon_size(IconSize::Small)
|
||||
.tooltip(move |cx| Tooltip::text("Remove All Context", cx))
|
||||
.on_click({
|
||||
let context_store = self.context_store.clone();
|
||||
cx.listener(move |_this, _event, cx| {
|
||||
context_store.update(cx, |this, _cx| this.clear());
|
||||
cx.notify();
|
||||
})
|
||||
}),
|
||||
)
|
||||
.when(!context.is_empty(), {
|
||||
move |parent| {
|
||||
parent.child(
|
||||
IconButton::new("remove-all-context", IconName::Eraser)
|
||||
.icon_size(IconSize::Small)
|
||||
.tooltip(move |cx| Tooltip::text("Remove All Context", cx))
|
||||
.on_click({
|
||||
let context_store = self.context_store.clone();
|
||||
cx.listener(move |_this, _event, cx| {
|
||||
context_store.update(cx, |this, _cx| this.clear());
|
||||
cx.notify();
|
||||
})
|
||||
}),
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ impl MessageEditor {
|
||||
|
||||
let editor = cx.new_view(|cx| {
|
||||
let mut editor = Editor::auto_height(10, cx);
|
||||
editor.set_placeholder_text("Ask anything, @ to add context", cx);
|
||||
editor.set_placeholder_text("Ask anything…", cx);
|
||||
editor.set_show_indent_guides(false, cx);
|
||||
|
||||
editor
|
||||
@@ -220,67 +220,73 @@ impl Render for MessageEditor {
|
||||
.p_2()
|
||||
.bg(bg_color)
|
||||
.child(self.context_strip.clone())
|
||||
.child({
|
||||
let settings = ThemeSettings::get_global(cx);
|
||||
let text_style = TextStyle {
|
||||
color: cx.theme().colors().editor_foreground,
|
||||
font_family: settings.ui_font.family.clone(),
|
||||
font_features: settings.ui_font.features.clone(),
|
||||
font_size: font_size.into(),
|
||||
font_weight: settings.ui_font.weight,
|
||||
line_height: line_height.into(),
|
||||
..Default::default()
|
||||
};
|
||||
.child(
|
||||
v_flex()
|
||||
.gap_4()
|
||||
.child({
|
||||
let settings = ThemeSettings::get_global(cx);
|
||||
let text_style = TextStyle {
|
||||
color: cx.theme().colors().text,
|
||||
font_family: settings.ui_font.family.clone(),
|
||||
font_features: settings.ui_font.features.clone(),
|
||||
font_size: font_size.into(),
|
||||
font_weight: settings.ui_font.weight,
|
||||
line_height: line_height.into(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
EditorElement::new(
|
||||
&self.editor,
|
||||
EditorStyle {
|
||||
background: bg_color,
|
||||
local_player: cx.theme().players().local(),
|
||||
text: text_style,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
})
|
||||
.child(
|
||||
PopoverMenu::new("inline-context-picker")
|
||||
.menu(move |_cx| Some(inline_context_picker.clone()))
|
||||
.attach(gpui::Corner::TopLeft)
|
||||
.anchor(gpui::Corner::BottomLeft)
|
||||
.offset(gpui::Point {
|
||||
x: px(0.0),
|
||||
y: px(-16.0),
|
||||
EditorElement::new(
|
||||
&self.editor,
|
||||
EditorStyle {
|
||||
background: bg_color,
|
||||
local_player: cx.theme().players().local(),
|
||||
text: text_style,
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
})
|
||||
.with_handle(self.inline_context_picker_menu_handle.clone()),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.justify_between()
|
||||
.child(SwitchWithLabel::new(
|
||||
"use-tools",
|
||||
Label::new("Tools"),
|
||||
self.use_tools.into(),
|
||||
cx.listener(|this, selection, _cx| {
|
||||
this.use_tools = match selection {
|
||||
ToggleState::Selected => true,
|
||||
ToggleState::Unselected | ToggleState::Indeterminate => false,
|
||||
};
|
||||
}),
|
||||
))
|
||||
.child(
|
||||
h_flex().gap_1().child(self.model_selector.clone()).child(
|
||||
ButtonLike::new("chat")
|
||||
.style(ButtonStyle::Filled)
|
||||
.layer(ElevationIndex::ModalSurface)
|
||||
.child(Label::new("Submit"))
|
||||
.children(
|
||||
KeyBinding::for_action_in(&Chat, &focus_handle, cx)
|
||||
.map(|binding| binding.into_any_element()),
|
||||
)
|
||||
.on_click(move |_event, cx| {
|
||||
focus_handle.dispatch_action(&Chat, cx);
|
||||
PopoverMenu::new("inline-context-picker")
|
||||
.menu(move |_cx| Some(inline_context_picker.clone()))
|
||||
.attach(gpui::Corner::TopLeft)
|
||||
.anchor(gpui::Corner::BottomLeft)
|
||||
.offset(gpui::Point {
|
||||
x: px(0.0),
|
||||
y: px(-16.0),
|
||||
})
|
||||
.with_handle(self.inline_context_picker_menu_handle.clone()),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.justify_between()
|
||||
.child(SwitchWithLabel::new(
|
||||
"use-tools",
|
||||
Label::new("Tools"),
|
||||
self.use_tools.into(),
|
||||
cx.listener(|this, selection, _cx| {
|
||||
this.use_tools = match selection {
|
||||
ToggleState::Selected => true,
|
||||
ToggleState::Unselected | ToggleState::Indeterminate => {
|
||||
false
|
||||
}
|
||||
};
|
||||
}),
|
||||
),
|
||||
))
|
||||
.child(
|
||||
h_flex().gap_1().child(self.model_selector.clone()).child(
|
||||
ButtonLike::new("chat")
|
||||
.style(ButtonStyle::Filled)
|
||||
.layer(ElevationIndex::ModalSurface)
|
||||
.child(Label::new("Submit"))
|
||||
.children(
|
||||
KeyBinding::for_action_in(&Chat, &focus_handle, cx)
|
||||
.map(|binding| binding.into_any_element()),
|
||||
)
|
||||
.on_click(move |_event, cx| {
|
||||
focus_handle.dispatch_action(&Chat, cx);
|
||||
}),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::rc::Rc;
|
||||
use gpui::ClickEvent;
|
||||
use ui::{prelude::*, IconButtonShape};
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::context::{Context, ContextKind};
|
||||
|
||||
#[derive(IntoElement)]
|
||||
pub struct ContextPill {
|
||||
@@ -27,15 +27,28 @@ impl ContextPill {
|
||||
|
||||
impl RenderOnce for ContextPill {
|
||||
fn render(self, cx: &mut WindowContext) -> impl IntoElement {
|
||||
let padding_right = if self.on_remove.is_some() {
|
||||
px(2.)
|
||||
} else {
|
||||
px(4.)
|
||||
};
|
||||
let icon = match self.context.kind {
|
||||
ContextKind::File => IconName::File,
|
||||
ContextKind::Directory => IconName::Folder,
|
||||
ContextKind::FetchedUrl => IconName::Globe,
|
||||
ContextKind::Thread => IconName::MessageCircle,
|
||||
};
|
||||
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.pl_1p5()
|
||||
.pr_0p5()
|
||||
.pl_1()
|
||||
.pr(padding_right)
|
||||
.pb(px(1.))
|
||||
.border_1()
|
||||
.border_color(cx.theme().colors().border.opacity(0.5))
|
||||
.bg(cx.theme().colors().element_background)
|
||||
.rounded_md()
|
||||
.child(Icon::new(icon).size(IconSize::XSmall).color(Color::Muted))
|
||||
.child(Label::new(self.context.name.clone()).size(LabelSize::Small))
|
||||
.when_some(self.on_remove, |parent, on_remove| {
|
||||
parent.child(
|
||||
|
||||
@@ -18,7 +18,7 @@ pub struct UpdateNotification {
|
||||
impl EventEmitter<DismissEvent> for UpdateNotification {}
|
||||
|
||||
impl Render for UpdateNotification {
|
||||
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
let app_name = ReleaseChannel::global(cx).display_name();
|
||||
|
||||
v_flex()
|
||||
|
||||
@@ -16,10 +16,10 @@ doctest = false
|
||||
editor.workspace = true
|
||||
gpui.workspace = true
|
||||
itertools.workspace = true
|
||||
outline.workspace = true
|
||||
theme.workspace = true
|
||||
ui.workspace = true
|
||||
workspace.workspace = true
|
||||
zed_actions.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
editor = { workspace = true, features = ["test-support"] }
|
||||
|
||||
@@ -102,8 +102,11 @@ impl Render for Breadcrumbs {
|
||||
.on_click({
|
||||
let editor = editor.clone();
|
||||
move |_, cx| {
|
||||
if let Some(editor) = editor.upgrade() {
|
||||
outline::toggle(editor, &editor::actions::ToggleOutline, cx)
|
||||
if let Some((editor, callback)) = editor
|
||||
.upgrade()
|
||||
.zip(zed_actions::outline::TOGGLE_OUTLINE.get())
|
||||
{
|
||||
callback(editor.to_any(), cx);
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -112,14 +115,14 @@ impl Render for Breadcrumbs {
|
||||
let focus_handle = editor.read(cx).focus_handle(cx);
|
||||
Tooltip::for_action_in(
|
||||
"Show Symbol Outline",
|
||||
&editor::actions::ToggleOutline,
|
||||
&zed_actions::outline::ToggleOutline,
|
||||
&focus_handle,
|
||||
cx,
|
||||
)
|
||||
} else {
|
||||
Tooltip::for_action(
|
||||
"Show Symbol Outline",
|
||||
&editor::actions::ToggleOutline,
|
||||
&zed_actions::outline::ToggleOutline,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ anyhow.workspace = true
|
||||
clap.workspace = true
|
||||
collections.workspace = true
|
||||
ipc-channel = "0.19"
|
||||
once_cell.workspace = true
|
||||
parking_lot.workspace = true
|
||||
paths.workspace = true
|
||||
release_channel.workspace = true
|
||||
|
||||
@@ -257,6 +257,7 @@ fn main() -> Result<()> {
|
||||
if args.foreground {
|
||||
app.run_foreground(url)?;
|
||||
} else {
|
||||
eprintln!("Logs are written to {:?}", paths::log_file());
|
||||
app.launch(url)?;
|
||||
sender.join().unwrap()?;
|
||||
pipe_handle.join().unwrap()?;
|
||||
@@ -277,6 +278,7 @@ mod linux {
|
||||
os::unix::net::{SocketAddr, UnixDatagram},
|
||||
path::{Path, PathBuf},
|
||||
process::{self, ExitStatus},
|
||||
sync::LazyLock,
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
@@ -284,12 +286,11 @@ mod linux {
|
||||
use anyhow::anyhow;
|
||||
use cli::FORCE_CLI_MODE_ENV_VAR_NAME;
|
||||
use fork::Fork;
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
use crate::{Detect, InstalledApp};
|
||||
|
||||
static RELEASE_CHANNEL: Lazy<String> =
|
||||
Lazy::new(|| include_str!("../../zed/RELEASE_CHANNEL").trim().to_string());
|
||||
static RELEASE_CHANNEL: LazyLock<String> =
|
||||
LazyLock::new(|| include_str!("../../zed/RELEASE_CHANNEL").trim().to_string());
|
||||
|
||||
struct App(PathBuf);
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ futures.workspace = true
|
||||
gpui.workspace = true
|
||||
http_client.workspace = true
|
||||
log.workspace = true
|
||||
once_cell.workspace = true
|
||||
paths.workspace = true
|
||||
parking_lot.workspace = true
|
||||
postage.workspace = true
|
||||
|
||||
@@ -8,7 +8,6 @@ use futures::channel::mpsc;
|
||||
use futures::{Future, StreamExt};
|
||||
use gpui::{AppContext, BackgroundExecutor, Task};
|
||||
use http_client::{self, AsyncBody, HttpClient, HttpClientWithUrl, Method, Request};
|
||||
use once_cell::sync::Lazy;
|
||||
use parking_lot::Mutex;
|
||||
use release_channel::ReleaseChannel;
|
||||
use settings::{Settings, SettingsStore};
|
||||
@@ -16,7 +15,12 @@ use sha2::{Digest, Sha256};
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::time::Instant;
|
||||
use std::{env, mem, path::PathBuf, sync::Arc, time::Duration};
|
||||
use std::{
|
||||
env, mem,
|
||||
path::PathBuf,
|
||||
sync::{Arc, LazyLock},
|
||||
time::Duration,
|
||||
};
|
||||
use telemetry_events::{
|
||||
AppEvent, AssistantEvent, CallEvent, EditEvent, Event, EventRequestBody, EventWrapper,
|
||||
InlineCompletionEvent,
|
||||
@@ -84,7 +88,7 @@ const FLUSH_INTERVAL: Duration = Duration::from_secs(1);
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
const FLUSH_INTERVAL: Duration = Duration::from_secs(60 * 5);
|
||||
static ZED_CLIENT_CHECKSUM_SEED: Lazy<Option<Vec<u8>>> = Lazy::new(|| {
|
||||
static ZED_CLIENT_CHECKSUM_SEED: LazyLock<Option<Vec<u8>>> = LazyLock::new(|| {
|
||||
option_env!("ZED_CLIENT_CHECKSUM_SEED")
|
||||
.map(|s| s.as_bytes().into())
|
||||
.or_else(|| {
|
||||
|
||||
@@ -1096,7 +1096,7 @@ impl FocusableView for ChatPanel {
|
||||
}
|
||||
|
||||
impl Panel for ChatPanel {
|
||||
fn position(&self, cx: &gpui::WindowContext) -> DockPosition {
|
||||
fn position(&self, cx: &WindowContext) -> DockPosition {
|
||||
ChatPanelSettings::get_global(cx).dock
|
||||
}
|
||||
|
||||
@@ -1112,7 +1112,7 @@ impl Panel for ChatPanel {
|
||||
);
|
||||
}
|
||||
|
||||
fn size(&self, cx: &gpui::WindowContext) -> Pixels {
|
||||
fn size(&self, cx: &WindowContext) -> Pixels {
|
||||
self.width
|
||||
.unwrap_or_else(|| ChatPanelSettings::get_global(cx).default_width)
|
||||
}
|
||||
@@ -1141,6 +1141,7 @@ impl Panel for ChatPanel {
|
||||
ChatPanelButton::WhenInCall => ActiveCall::global(cx)
|
||||
.read(cx)
|
||||
.room()
|
||||
.filter(|room| room.read(cx).contains_guests())
|
||||
.map(|_| ui::IconName::MessageBubbles),
|
||||
}
|
||||
}
|
||||
@@ -1159,6 +1160,10 @@ impl Panel for ChatPanel {
|
||||
.room()
|
||||
.is_some_and(|room| room.read(cx).contains_guests())
|
||||
}
|
||||
|
||||
fn activation_priority(&self) -> u32 {
|
||||
7
|
||||
}
|
||||
}
|
||||
|
||||
impl EventEmitter<PanelEvent> for ChatPanel {}
|
||||
|
||||
@@ -79,16 +79,6 @@ impl CompletionProvider for MessageEditorCompletionProvider {
|
||||
Task::ready(Ok(false))
|
||||
}
|
||||
|
||||
fn apply_additional_edits_for_completion(
|
||||
&self,
|
||||
_buffer: Model<Buffer>,
|
||||
_completion: Completion,
|
||||
_push_to_history: bool,
|
||||
_cx: &mut ViewContext<Editor>,
|
||||
) -> Task<Result<Option<language::Transaction>>> {
|
||||
Task::ready(Ok(None))
|
||||
}
|
||||
|
||||
fn is_completion_trigger(
|
||||
&self,
|
||||
_buffer: &Model<Buffer>,
|
||||
@@ -319,6 +309,7 @@ impl MessageEditor {
|
||||
server_id: LanguageServerId(0), // TODO: Make this optional or something?
|
||||
lsp_completion: Default::default(), // TODO: Make this optional or something?
|
||||
confirm: None,
|
||||
resolved: true,
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
|
||||
@@ -2719,7 +2719,7 @@ impl Render for CollabPanel {
|
||||
impl EventEmitter<PanelEvent> for CollabPanel {}
|
||||
|
||||
impl Panel for CollabPanel {
|
||||
fn position(&self, cx: &gpui::WindowContext) -> DockPosition {
|
||||
fn position(&self, cx: &WindowContext) -> DockPosition {
|
||||
CollaborationPanelSettings::get_global(cx).dock
|
||||
}
|
||||
|
||||
@@ -2735,7 +2735,7 @@ impl Panel for CollabPanel {
|
||||
);
|
||||
}
|
||||
|
||||
fn size(&self, cx: &gpui::WindowContext) -> Pixels {
|
||||
fn size(&self, cx: &WindowContext) -> Pixels {
|
||||
self.width
|
||||
.unwrap_or_else(|| CollaborationPanelSettings::get_global(cx).default_width)
|
||||
}
|
||||
@@ -2746,7 +2746,7 @@ impl Panel for CollabPanel {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn icon(&self, cx: &gpui::WindowContext) -> Option<ui::IconName> {
|
||||
fn icon(&self, cx: &WindowContext) -> Option<ui::IconName> {
|
||||
CollaborationPanelSettings::get_global(cx)
|
||||
.button
|
||||
.then_some(ui::IconName::UserGroup)
|
||||
@@ -2763,6 +2763,10 @@ impl Panel for CollabPanel {
|
||||
fn persistent_name() -> &'static str {
|
||||
"CollabPanel"
|
||||
}
|
||||
|
||||
fn activation_priority(&self) -> u32 {
|
||||
6
|
||||
}
|
||||
}
|
||||
|
||||
impl FocusableView for CollabPanel {
|
||||
|
||||
@@ -662,7 +662,7 @@ impl Panel for NotificationPanel {
|
||||
"NotificationPanel"
|
||||
}
|
||||
|
||||
fn position(&self, cx: &gpui::WindowContext) -> DockPosition {
|
||||
fn position(&self, cx: &WindowContext) -> DockPosition {
|
||||
NotificationPanelSettings::get_global(cx).dock
|
||||
}
|
||||
|
||||
@@ -678,7 +678,7 @@ impl Panel for NotificationPanel {
|
||||
);
|
||||
}
|
||||
|
||||
fn size(&self, cx: &gpui::WindowContext) -> Pixels {
|
||||
fn size(&self, cx: &WindowContext) -> Pixels {
|
||||
self.width
|
||||
.unwrap_or_else(|| NotificationPanelSettings::get_global(cx).default_width)
|
||||
}
|
||||
@@ -702,7 +702,7 @@ impl Panel for NotificationPanel {
|
||||
}
|
||||
}
|
||||
|
||||
fn icon(&self, cx: &gpui::WindowContext) -> Option<IconName> {
|
||||
fn icon(&self, cx: &WindowContext) -> Option<IconName> {
|
||||
let show_button = NotificationPanelSettings::get_global(cx).button;
|
||||
if !show_button {
|
||||
return None;
|
||||
@@ -731,6 +731,10 @@ impl Panel for NotificationPanel {
|
||||
fn toggle_action(&self) -> Box<dyn gpui::Action> {
|
||||
Box::new(ToggleFocus)
|
||||
}
|
||||
|
||||
fn activation_priority(&self) -> u32 {
|
||||
8
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NotificationToast {
|
||||
|
||||
@@ -28,7 +28,6 @@ serde.workspace = true
|
||||
serde_json.workspace = true
|
||||
settings.workspace = true
|
||||
smol.workspace = true
|
||||
ui.workspace = true
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
util.workspace = true
|
||||
workspace.workspace = true
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::sync::Arc;
|
||||
|
||||
use anyhow::{anyhow, bail};
|
||||
use assistant_tool::Tool;
|
||||
use gpui::{Model, Task};
|
||||
use gpui::{Model, Task, WindowContext};
|
||||
|
||||
use crate::manager::ContextServerManager;
|
||||
use crate::types;
|
||||
@@ -52,7 +52,7 @@ impl Tool for ContextServerTool {
|
||||
self: std::sync::Arc<Self>,
|
||||
input: serde_json::Value,
|
||||
_workspace: gpui::WeakView<workspace::Workspace>,
|
||||
cx: &mut ui::WindowContext,
|
||||
cx: &mut WindowContext,
|
||||
) -> gpui::Task<gpui::Result<String>> {
|
||||
if let Some(server) = self.server_manager.read(cx).get_server(&self.server_id) {
|
||||
cx.foreground_executor().spawn({
|
||||
|
||||
@@ -34,9 +34,9 @@ pub enum Model {
|
||||
Gpt4,
|
||||
#[serde(alias = "gpt-3.5-turbo", rename = "gpt-3.5-turbo")]
|
||||
Gpt3_5Turbo,
|
||||
#[serde(alias = "o1-preview", rename = "o1-preview-2024-09-12")]
|
||||
#[serde(alias = "o1-preview", rename = "o1")]
|
||||
O1Preview,
|
||||
#[serde(alias = "o1-mini", rename = "o1-mini-2024-09-12")]
|
||||
#[serde(alias = "o1-mini", rename = "o1-mini")]
|
||||
O1Mini,
|
||||
#[serde(alias = "claude-3-5-sonnet", rename = "claude-3.5-sonnet")]
|
||||
Claude3_5Sonnet,
|
||||
|
||||
@@ -166,7 +166,7 @@ impl ProjectDiagnosticsEditor {
|
||||
let excerpts = cx.new_model(|cx| MultiBuffer::new(project_handle.read(cx).capability()));
|
||||
let editor = cx.new_view(|cx| {
|
||||
let mut editor =
|
||||
Editor::for_multibuffer(excerpts.clone(), Some(project_handle.clone()), false, cx);
|
||||
Editor::for_multibuffer(excerpts.clone(), Some(project_handle.clone()), true, cx);
|
||||
editor.set_vertical_scroll_margin(5, cx);
|
||||
editor
|
||||
});
|
||||
@@ -836,65 +836,76 @@ fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock {
|
||||
let (message, code_ranges) = highlight_diagnostic_message(&diagnostic, None);
|
||||
let message: SharedString = message;
|
||||
Arc::new(move |cx| {
|
||||
let highlight_style: HighlightStyle = cx.theme().colors().text_accent.into();
|
||||
let color = cx.theme().colors();
|
||||
let highlight_style: HighlightStyle = color.text_accent.into();
|
||||
|
||||
h_flex()
|
||||
.id(DIAGNOSTIC_HEADER)
|
||||
.block_mouse_down()
|
||||
.h(2. * cx.line_height())
|
||||
.pl_10()
|
||||
.pr_5()
|
||||
.w_full()
|
||||
.justify_between()
|
||||
.gap_2()
|
||||
.relative()
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_3()
|
||||
.map(|stack| {
|
||||
stack.child(
|
||||
svg()
|
||||
.size(cx.text_style().font_size)
|
||||
.flex_none()
|
||||
.map(|icon| {
|
||||
if diagnostic.severity == DiagnosticSeverity::ERROR {
|
||||
icon.path(IconName::XCircle.path())
|
||||
.text_color(Color::Error.color(cx))
|
||||
} else {
|
||||
icon.path(IconName::Warning.path())
|
||||
.text_color(Color::Warning.color(cx))
|
||||
}
|
||||
}),
|
||||
)
|
||||
})
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.child(
|
||||
StyledText::new(message.clone()).with_highlights(
|
||||
&cx.text_style(),
|
||||
code_ranges
|
||||
.iter()
|
||||
.map(|range| (range.clone(), highlight_style)),
|
||||
),
|
||||
)
|
||||
.when_some(diagnostic.code.as_ref(), |stack, code| {
|
||||
stack.child(
|
||||
div()
|
||||
.child(SharedString::from(format!("({code})")))
|
||||
.text_color(cx.theme().colors().text_muted),
|
||||
)
|
||||
}),
|
||||
),
|
||||
div()
|
||||
.top(px(0.))
|
||||
.absolute()
|
||||
.w_full()
|
||||
.h_px()
|
||||
.bg(color.border_variant),
|
||||
)
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.when_some(diagnostic.source.as_ref(), |stack, source| {
|
||||
stack.child(
|
||||
div()
|
||||
.child(SharedString::from(source.clone()))
|
||||
.text_color(cx.theme().colors().text_muted),
|
||||
)
|
||||
}),
|
||||
.block_mouse_down()
|
||||
.h(2. * cx.line_height())
|
||||
.pl_10()
|
||||
.pr_5()
|
||||
.w_full()
|
||||
.justify_between()
|
||||
.gap_2()
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_3()
|
||||
.map(|stack| {
|
||||
stack.child(svg().size(cx.text_style().font_size).flex_none().map(
|
||||
|icon| {
|
||||
if diagnostic.severity == DiagnosticSeverity::ERROR {
|
||||
icon.path(IconName::XCircle.path())
|
||||
.text_color(Color::Error.color(cx))
|
||||
} else {
|
||||
icon.path(IconName::Warning.path())
|
||||
.text_color(Color::Warning.color(cx))
|
||||
}
|
||||
},
|
||||
))
|
||||
})
|
||||
.child(
|
||||
h_flex()
|
||||
.gap_1()
|
||||
.child(
|
||||
StyledText::new(message.clone()).with_highlights(
|
||||
&cx.text_style(),
|
||||
code_ranges
|
||||
.iter()
|
||||
.map(|range| (range.clone(), highlight_style)),
|
||||
),
|
||||
)
|
||||
.when_some(diagnostic.code.as_ref(), |stack, code| {
|
||||
stack.child(
|
||||
div()
|
||||
.child(SharedString::from(format!("({code})")))
|
||||
.text_color(cx.theme().colors().text_muted),
|
||||
)
|
||||
}),
|
||||
),
|
||||
)
|
||||
.child(h_flex().gap_1().when_some(
|
||||
diagnostic.source.as_ref(),
|
||||
|stack, source| {
|
||||
stack.child(
|
||||
div()
|
||||
.child(SharedString::from(source.clone()))
|
||||
.text_color(cx.theme().colors().text_muted),
|
||||
)
|
||||
},
|
||||
)),
|
||||
)
|
||||
.into_any_element()
|
||||
})
|
||||
|
||||
@@ -167,10 +167,10 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
editor_blocks(&editor, cx),
|
||||
[
|
||||
(DisplayRow(0), FILE_HEADER.into()),
|
||||
(DisplayRow(2), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(15), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(16), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(25), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(3), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(16), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(18), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(27), EXCERPT_HEADER.into()),
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -184,6 +184,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
// diagnostic group 1
|
||||
"\n", // primary message
|
||||
"\n", // padding
|
||||
"\n", // expand
|
||||
" let x = vec![];\n",
|
||||
" let y = vec![];\n",
|
||||
"\n", // supporting diagnostic
|
||||
@@ -195,6 +196,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
" c(y);\n",
|
||||
"\n", // supporting diagnostic
|
||||
" d(x);\n",
|
||||
"\n", // expand
|
||||
"\n", // context ellipsis
|
||||
// diagnostic group 2
|
||||
"\n", // primary message
|
||||
@@ -206,11 +208,13 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
" a(x);\n",
|
||||
"\n", // supporting diagnostic
|
||||
" b(y);\n",
|
||||
"\n", // expand
|
||||
"\n", // context ellipsis
|
||||
" c(y);\n",
|
||||
" d(x);\n",
|
||||
"\n", // supporting diagnostic
|
||||
"}"
|
||||
"}",
|
||||
"\n", // expand
|
||||
)
|
||||
);
|
||||
|
||||
@@ -218,7 +222,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
editor.update(cx, |editor, cx| {
|
||||
assert_eq!(
|
||||
editor.selections.display_ranges(cx),
|
||||
[DisplayPoint::new(DisplayRow(12), 6)..DisplayPoint::new(DisplayRow(12), 6)]
|
||||
[DisplayPoint::new(DisplayRow(13), 6)..DisplayPoint::new(DisplayRow(13), 6)]
|
||||
);
|
||||
});
|
||||
|
||||
@@ -253,12 +257,12 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
editor_blocks(&editor, cx),
|
||||
[
|
||||
(DisplayRow(0), FILE_HEADER.into()),
|
||||
(DisplayRow(2), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(7), FILE_HEADER.into()),
|
||||
(DisplayRow(9), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(22), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(23), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(32), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(3), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(8), FILE_HEADER.into()),
|
||||
(DisplayRow(12), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(25), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(27), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(36), EXCERPT_HEADER.into()),
|
||||
]
|
||||
);
|
||||
|
||||
@@ -273,6 +277,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
// diagnostic group 1
|
||||
"\n", // primary message
|
||||
"\n", // padding
|
||||
"\n", // expand
|
||||
"const a: i32 = 'a';\n",
|
||||
"\n", // supporting diagnostic
|
||||
"const b: i32 = c;\n",
|
||||
@@ -284,6 +289,8 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
// diagnostic group 1
|
||||
"\n", // primary message
|
||||
"\n", // padding
|
||||
"\n", // expand
|
||||
"\n", // expand
|
||||
" let x = vec![];\n",
|
||||
" let y = vec![];\n",
|
||||
"\n", // supporting diagnostic
|
||||
@@ -299,6 +306,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
// diagnostic group 2
|
||||
"\n", // primary message
|
||||
"\n", // filename
|
||||
"\n", // expand
|
||||
"fn main() {\n",
|
||||
" let x = vec![];\n",
|
||||
"\n", // supporting diagnostic
|
||||
@@ -306,11 +314,13 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
" a(x);\n",
|
||||
"\n", // supporting diagnostic
|
||||
" b(y);\n",
|
||||
"\n", // expand
|
||||
"\n", // context ellipsis
|
||||
" c(y);\n",
|
||||
" d(x);\n",
|
||||
"\n", // supporting diagnostic
|
||||
"}"
|
||||
"}",
|
||||
"\n", // expand
|
||||
)
|
||||
);
|
||||
|
||||
@@ -318,7 +328,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
editor.update(cx, |editor, cx| {
|
||||
assert_eq!(
|
||||
editor.selections.display_ranges(cx),
|
||||
[DisplayPoint::new(DisplayRow(19), 6)..DisplayPoint::new(DisplayRow(19), 6)]
|
||||
[DisplayPoint::new(DisplayRow(22), 6)..DisplayPoint::new(DisplayRow(22), 6)]
|
||||
);
|
||||
});
|
||||
|
||||
@@ -366,14 +376,14 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
editor_blocks(&editor, cx),
|
||||
[
|
||||
(DisplayRow(0), FILE_HEADER.into()),
|
||||
(DisplayRow(2), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(7), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(8), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(13), FILE_HEADER.into()),
|
||||
(DisplayRow(15), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(28), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(29), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(38), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(3), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(8), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(10), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(15), FILE_HEADER.into()),
|
||||
(DisplayRow(19), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(32), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(34), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(43), EXCERPT_HEADER.into()),
|
||||
]
|
||||
);
|
||||
|
||||
@@ -388,6 +398,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
// diagnostic group 1
|
||||
"\n", // primary message
|
||||
"\n", // padding
|
||||
"\n", // expand
|
||||
"const a: i32 = 'a';\n",
|
||||
"\n", // supporting diagnostic
|
||||
"const b: i32 = c;\n",
|
||||
@@ -395,6 +406,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
// diagnostic group 2
|
||||
"\n", // primary message
|
||||
"\n", // padding
|
||||
"\n", // expand
|
||||
"const a: i32 = 'a';\n",
|
||||
"const b: i32 = c;\n",
|
||||
"\n", // supporting diagnostic
|
||||
@@ -406,6 +418,8 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
// diagnostic group 1
|
||||
"\n", // primary message
|
||||
"\n", // padding
|
||||
"\n", // expand
|
||||
"\n", // expand
|
||||
" let x = vec![];\n",
|
||||
" let y = vec![];\n",
|
||||
"\n", // supporting diagnostic
|
||||
@@ -421,6 +435,7 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
// diagnostic group 2
|
||||
"\n", // primary message
|
||||
"\n", // filename
|
||||
"\n", // expand
|
||||
"fn main() {\n",
|
||||
" let x = vec![];\n",
|
||||
"\n", // supporting diagnostic
|
||||
@@ -428,11 +443,13 @@ async fn test_diagnostics(cx: &mut TestAppContext) {
|
||||
" a(x);\n",
|
||||
"\n", // supporting diagnostic
|
||||
" b(y);\n",
|
||||
"\n", // expand
|
||||
"\n", // context ellipsis
|
||||
" c(y);\n",
|
||||
" d(x);\n",
|
||||
"\n", // supporting diagnostic
|
||||
"}"
|
||||
"}",
|
||||
"\n", // expand
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -513,7 +530,7 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
|
||||
editor_blocks(&editor, cx),
|
||||
[
|
||||
(DisplayRow(0), FILE_HEADER.into()),
|
||||
(DisplayRow(2), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(3), DIAGNOSTIC_HEADER.into()),
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -524,8 +541,9 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
|
||||
// diagnostic group 1
|
||||
"\n", // primary message
|
||||
"\n", // padding
|
||||
"\n", // expand
|
||||
"a();\n", //
|
||||
"b();",
|
||||
"b();", "\n", // expand
|
||||
)
|
||||
);
|
||||
|
||||
@@ -561,9 +579,9 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
|
||||
editor_blocks(&editor, cx),
|
||||
[
|
||||
(DisplayRow(0), FILE_HEADER.into()),
|
||||
(DisplayRow(2), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(6), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(7), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(3), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(7), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(9), DIAGNOSTIC_HEADER.into()),
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -574,8 +592,10 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
|
||||
// diagnostic group 1
|
||||
"\n", // primary message
|
||||
"\n", // padding
|
||||
"\n", // expand
|
||||
"a();\n", // location
|
||||
"b();\n", //
|
||||
"\n", // expand
|
||||
"\n", // collapsed context
|
||||
// diagnostic group 2
|
||||
"\n", // primary message
|
||||
@@ -583,6 +603,7 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
|
||||
"a();\n", // context
|
||||
"b();\n", //
|
||||
"c();", // context
|
||||
"\n", // expand
|
||||
)
|
||||
);
|
||||
|
||||
@@ -629,9 +650,9 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
|
||||
editor_blocks(&editor, cx),
|
||||
[
|
||||
(DisplayRow(0), FILE_HEADER.into()),
|
||||
(DisplayRow(2), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(7), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(8), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(3), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(8), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(10), DIAGNOSTIC_HEADER.into()),
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -642,9 +663,11 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
|
||||
// diagnostic group 1
|
||||
"\n", // primary message
|
||||
"\n", // padding
|
||||
"\n", // expand
|
||||
"a();\n", // location
|
||||
"b();\n", //
|
||||
"c();\n", // context
|
||||
"\n", // expand
|
||||
"\n", // collapsed context
|
||||
// diagnostic group 2
|
||||
"\n", // primary message
|
||||
@@ -652,6 +675,7 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
|
||||
"b();\n", // context
|
||||
"c();\n", //
|
||||
"d();", // context
|
||||
"\n", // expand
|
||||
)
|
||||
);
|
||||
|
||||
@@ -687,9 +711,9 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
|
||||
editor_blocks(&editor, cx),
|
||||
[
|
||||
(DisplayRow(0), FILE_HEADER.into()),
|
||||
(DisplayRow(2), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(7), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(8), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(3), DIAGNOSTIC_HEADER.into()),
|
||||
(DisplayRow(8), EXCERPT_HEADER.into()),
|
||||
(DisplayRow(10), DIAGNOSTIC_HEADER.into()),
|
||||
]
|
||||
);
|
||||
assert_eq!(
|
||||
@@ -700,9 +724,11 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
|
||||
// diagnostic group 1
|
||||
"\n", // primary message
|
||||
"\n", // padding
|
||||
"\n", // expand
|
||||
"b();\n", // location
|
||||
"c();\n", //
|
||||
"d();\n", // context
|
||||
"\n", // expand
|
||||
"\n", // collapsed context
|
||||
// diagnostic group 2
|
||||
"\n", // primary message
|
||||
@@ -710,6 +736,7 @@ async fn test_diagnostics_multiple_servers(cx: &mut TestAppContext) {
|
||||
"c();\n", // context
|
||||
"d();\n", //
|
||||
"e();", // context
|
||||
"\n", // expand
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -388,6 +388,4 @@ gpui::actions!(
|
||||
]
|
||||
);
|
||||
|
||||
action_as!(outline, ToggleOutline as Toggle);
|
||||
|
||||
action_as!(go_to_line, ToggleGoToLine as Toggle);
|
||||
|
||||
@@ -16,7 +16,7 @@ fn is_c_language(language: &Language) -> bool {
|
||||
pub fn switch_source_header(
|
||||
editor: &mut Editor,
|
||||
_: &SwitchSourceHeader,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
let Some(project) = &editor.project else {
|
||||
return;
|
||||
|
||||
@@ -224,6 +224,7 @@ impl CompletionsMenu {
|
||||
documentation: None,
|
||||
lsp_completion: Default::default(),
|
||||
confirm: None,
|
||||
resolved: true,
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ use crate::{
|
||||
pub use block_map::{
|
||||
Block, BlockBufferRows, BlockChunks as DisplayChunks, BlockContext, BlockId, BlockMap,
|
||||
BlockPlacement, BlockPoint, BlockProperties, BlockStyle, CustomBlockId, RenderBlock,
|
||||
StickyHeaderExcerpt,
|
||||
};
|
||||
use block_map::{BlockRow, BlockSnapshot};
|
||||
use collections::{HashMap, HashSet};
|
||||
@@ -1105,6 +1106,10 @@ impl DisplaySnapshot {
|
||||
.map(|(row, block)| (DisplayRow(row), block))
|
||||
}
|
||||
|
||||
pub fn sticky_header_excerpt(&self, row: DisplayRow) -> Option<StickyHeaderExcerpt<'_>> {
|
||||
self.block_snapshot.sticky_header_excerpt(row.0)
|
||||
}
|
||||
|
||||
pub fn block_for_id(&self, id: BlockId) -> Option<Block> {
|
||||
self.block_snapshot.block_for_id(id)
|
||||
}
|
||||
|
||||
@@ -1411,6 +1411,66 @@ impl BlockSnapshot {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn sticky_header_excerpt(&self, top_row: u32) -> Option<StickyHeaderExcerpt<'_>> {
|
||||
let mut cursor = self.transforms.cursor::<BlockRow>(&());
|
||||
cursor.seek(&BlockRow(top_row), Bias::Left, &());
|
||||
|
||||
while let Some(transform) = cursor.item() {
|
||||
let start = cursor.start().0;
|
||||
let end = cursor.end(&()).0;
|
||||
|
||||
match &transform.block {
|
||||
Some(Block::ExcerptBoundary {
|
||||
prev_excerpt,
|
||||
next_excerpt,
|
||||
starts_new_buffer,
|
||||
show_excerpt_controls,
|
||||
..
|
||||
}) => {
|
||||
let matches_start = if *show_excerpt_controls && prev_excerpt.is_some() {
|
||||
start < top_row
|
||||
} else {
|
||||
start <= top_row
|
||||
};
|
||||
|
||||
if matches_start && top_row <= end {
|
||||
return next_excerpt.as_ref().map(|excerpt| StickyHeaderExcerpt {
|
||||
next_buffer_row: None,
|
||||
next_excerpt_controls_present: *show_excerpt_controls,
|
||||
excerpt,
|
||||
});
|
||||
}
|
||||
|
||||
let next_buffer_row = if *starts_new_buffer { Some(end) } else { None };
|
||||
|
||||
return prev_excerpt.as_ref().map(|excerpt| StickyHeaderExcerpt {
|
||||
excerpt,
|
||||
next_buffer_row,
|
||||
next_excerpt_controls_present: *show_excerpt_controls,
|
||||
});
|
||||
}
|
||||
Some(Block::FoldedBuffer {
|
||||
prev_excerpt: Some(excerpt),
|
||||
..
|
||||
}) if top_row <= start => {
|
||||
return Some(StickyHeaderExcerpt {
|
||||
next_buffer_row: Some(end),
|
||||
next_excerpt_controls_present: false,
|
||||
excerpt,
|
||||
});
|
||||
}
|
||||
Some(Block::FoldedBuffer { .. }) | Some(Block::Custom(_)) | None => {}
|
||||
}
|
||||
|
||||
// This is needed to iterate past None / FoldedBuffer / Custom blocks. For FoldedBuffer,
|
||||
// if scrolled slightly past the header of a folded block, the next block is needed for
|
||||
// the sticky header.
|
||||
cursor.next(&());
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn block_for_id(&self, block_id: BlockId) -> Option<Block> {
|
||||
let buffer = self.wrap_snapshot.buffer_snapshot();
|
||||
let wrap_point = match block_id {
|
||||
@@ -1694,6 +1754,13 @@ impl<'a> BlockChunks<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StickyHeaderExcerpt<'a> {
|
||||
pub excerpt: &'a ExcerptInfo,
|
||||
pub next_excerpt_controls_present: bool,
|
||||
// TODO az remove option
|
||||
pub next_buffer_row: Option<u32>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for BlockChunks<'a> {
|
||||
type Item = Chunk<'a>;
|
||||
|
||||
|
||||
@@ -992,12 +992,14 @@ pub(crate) struct FocusedBlock {
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct JumpData {
|
||||
excerpt_id: ExcerptId,
|
||||
position: Point,
|
||||
anchor: text::Anchor,
|
||||
path: Option<project::ProjectPath>,
|
||||
line_offset_from_top: u32,
|
||||
enum JumpData {
|
||||
MultiBufferRow(MultiBufferRow),
|
||||
MultiBufferPoint {
|
||||
excerpt_id: ExcerptId,
|
||||
position: Point,
|
||||
anchor: text::Anchor,
|
||||
line_offset_from_top: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl Editor {
|
||||
@@ -3513,7 +3515,7 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
fn visible_inlay_hints(&self, cx: &ViewContext<'_, Editor>) -> Vec<Inlay> {
|
||||
fn visible_inlay_hints(&self, cx: &ViewContext<Editor>) -> Vec<Inlay> {
|
||||
self.display_map
|
||||
.read(cx)
|
||||
.current_inlays()
|
||||
@@ -3830,8 +3832,11 @@ impl Editor {
|
||||
};
|
||||
|
||||
let buffer_handle = completions_menu.buffer;
|
||||
let completions = completions_menu.completions.borrow_mut();
|
||||
let completion = completions.get(mat.candidate_id)?;
|
||||
let completion = completions_menu
|
||||
.completions
|
||||
.borrow()
|
||||
.get(mat.candidate_id)?
|
||||
.clone();
|
||||
cx.stop_propagation();
|
||||
|
||||
let snippet;
|
||||
@@ -3975,9 +3980,11 @@ impl Editor {
|
||||
}
|
||||
|
||||
let provider = self.completion_provider.as_ref()?;
|
||||
drop(completion);
|
||||
let apply_edits = provider.apply_additional_edits_for_completion(
|
||||
buffer_handle,
|
||||
completion.clone(),
|
||||
completions_menu.completions.clone(),
|
||||
mat.candidate_id,
|
||||
true,
|
||||
cx,
|
||||
);
|
||||
@@ -5087,7 +5094,7 @@ impl Editor {
|
||||
}))
|
||||
}
|
||||
|
||||
#[cfg(feature = "test-support")]
|
||||
#[cfg(any(feature = "test-support", test))]
|
||||
pub fn context_menu_visible(&self) -> bool {
|
||||
self.context_menu
|
||||
.borrow()
|
||||
@@ -6004,7 +6011,7 @@ impl Editor {
|
||||
fn gather_revert_changes(
|
||||
&mut self,
|
||||
selections: &[Selection<Point>],
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>> {
|
||||
let mut revert_changes = HashMap::default();
|
||||
let snapshot = self.snapshot(cx);
|
||||
@@ -8931,7 +8938,7 @@ impl Editor {
|
||||
fn templates_with_tags(
|
||||
project: &Model<Project>,
|
||||
runnable: &mut Runnable,
|
||||
cx: &WindowContext<'_>,
|
||||
cx: &WindowContext,
|
||||
) -> Vec<(TaskSourceKind, TaskTemplate)> {
|
||||
let (inventory, worktree_id, file) = project.read_with(cx, |project, cx| {
|
||||
let (worktree_id, file) = project
|
||||
@@ -9243,7 +9250,7 @@ impl Editor {
|
||||
&mut self,
|
||||
snapshot: &EditorSnapshot,
|
||||
position: Point,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> Option<MultiBufferDiffHunk> {
|
||||
for (ix, position) in [position, Point::zero()].into_iter().enumerate() {
|
||||
if let Some(hunk) = self.go_to_next_hunk_in_direction(
|
||||
@@ -9272,7 +9279,7 @@ impl Editor {
|
||||
&mut self,
|
||||
snapshot: &EditorSnapshot,
|
||||
position: Point,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> Option<MultiBufferDiffHunk> {
|
||||
for (ix, position) in [position, snapshot.buffer_snapshot.max_point()]
|
||||
.into_iter()
|
||||
@@ -12453,28 +12460,46 @@ impl Editor {
|
||||
|
||||
let mut new_selections_by_buffer = HashMap::default();
|
||||
match &jump_data {
|
||||
Some(jump_data) => {
|
||||
Some(JumpData::MultiBufferPoint {
|
||||
excerpt_id,
|
||||
position,
|
||||
anchor,
|
||||
line_offset_from_top,
|
||||
}) => {
|
||||
let multi_buffer_snapshot = self.buffer.read(cx).snapshot(cx);
|
||||
if let Some(buffer) = multi_buffer_snapshot
|
||||
.buffer_id_for_excerpt(jump_data.excerpt_id)
|
||||
.buffer_id_for_excerpt(*excerpt_id)
|
||||
.and_then(|buffer_id| self.buffer.read(cx).buffer(buffer_id))
|
||||
{
|
||||
let buffer_snapshot = buffer.read(cx).snapshot();
|
||||
let jump_to_point = if buffer_snapshot.can_resolve(&jump_data.anchor) {
|
||||
language::ToPoint::to_point(&jump_data.anchor, &buffer_snapshot)
|
||||
let jump_to_point = if buffer_snapshot.can_resolve(anchor) {
|
||||
language::ToPoint::to_point(anchor, &buffer_snapshot)
|
||||
} else {
|
||||
buffer_snapshot.clip_point(jump_data.position, Bias::Left)
|
||||
buffer_snapshot.clip_point(*position, Bias::Left)
|
||||
};
|
||||
let jump_to_offset = buffer_snapshot.point_to_offset(jump_to_point);
|
||||
new_selections_by_buffer.insert(
|
||||
buffer,
|
||||
(
|
||||
vec![jump_to_offset..jump_to_offset],
|
||||
Some(jump_data.line_offset_from_top),
|
||||
Some(*line_offset_from_top),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Some(JumpData::MultiBufferRow(row)) => {
|
||||
let point = MultiBufferPoint::new(row.0, 0);
|
||||
if let Some((buffer, buffer_point, _)) =
|
||||
self.buffer.read(cx).point_to_buffer_point(point, cx)
|
||||
{
|
||||
let buffer_offset = buffer.read(cx).point_to_offset(buffer_point);
|
||||
new_selections_by_buffer
|
||||
.entry(buffer)
|
||||
.or_insert((Vec::new(), None))
|
||||
.0
|
||||
.push(buffer_offset..buffer_offset)
|
||||
}
|
||||
}
|
||||
None => {
|
||||
let selections = self.selections.all::<usize>(cx);
|
||||
let buffer = self.buffer.read(cx);
|
||||
@@ -13447,11 +13472,14 @@ pub trait CompletionProvider {
|
||||
|
||||
fn apply_additional_edits_for_completion(
|
||||
&self,
|
||||
buffer: Model<Buffer>,
|
||||
completion: Completion,
|
||||
push_to_history: bool,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> Task<Result<Option<language::Transaction>>>;
|
||||
_buffer: Model<Buffer>,
|
||||
_completions: Rc<RefCell<Box<[Completion]>>>,
|
||||
_completion_index: usize,
|
||||
_push_to_history: bool,
|
||||
_cx: &mut ViewContext<Editor>,
|
||||
) -> Task<Result<Option<language::Transaction>>> {
|
||||
Task::ready(Ok(None))
|
||||
}
|
||||
|
||||
fn is_completion_trigger(
|
||||
&self,
|
||||
@@ -13610,6 +13638,7 @@ fn snippet_completions(
|
||||
Some(Completion {
|
||||
old_range: range,
|
||||
new_text: snippet.body.clone(),
|
||||
resolved: false,
|
||||
label: CodeLabel {
|
||||
text: matching_prefix.clone(),
|
||||
runs: vec![],
|
||||
@@ -13675,19 +13704,30 @@ impl CompletionProvider for Model<Project> {
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> Task<Result<bool>> {
|
||||
self.update(cx, |project, cx| {
|
||||
project.resolve_completions(buffer, completion_indices, completions, cx)
|
||||
project.lsp_store().update(cx, |lsp_store, cx| {
|
||||
lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn apply_additional_edits_for_completion(
|
||||
&self,
|
||||
buffer: Model<Buffer>,
|
||||
completion: Completion,
|
||||
completions: Rc<RefCell<Box<[Completion]>>>,
|
||||
completion_index: usize,
|
||||
push_to_history: bool,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> Task<Result<Option<language::Transaction>>> {
|
||||
self.update(cx, |project, cx| {
|
||||
project.apply_additional_edits_for_completion(buffer, completion, push_to_history, cx)
|
||||
project.lsp_store().update(cx, |lsp_store, cx| {
|
||||
lsp_store.apply_additional_edits_for_completion(
|
||||
buffer,
|
||||
completions,
|
||||
completion_index,
|
||||
push_to_history,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -13822,7 +13862,7 @@ impl SemanticsProvider for Model<Project> {
|
||||
fn inlay_hint_settings(
|
||||
location: Anchor,
|
||||
snapshot: &MultiBufferSnapshot,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> InlayHintSettings {
|
||||
let file = snapshot.file_at(location);
|
||||
let language = snapshot.language_at(location).map(|l| l.name());
|
||||
|
||||
@@ -8402,7 +8402,6 @@ async fn test_completion(cx: &mut gpui::TestAppContext) {
|
||||
additional edit
|
||||
"});
|
||||
|
||||
handle_resolve_completion_request(&mut cx, None).await;
|
||||
apply_additional_edits.await.unwrap();
|
||||
|
||||
update_test_language_settings(&mut cx, |settings| {
|
||||
@@ -10698,10 +10697,14 @@ async fn test_completions_resolve_updates_labels_if_filter_text_matches(
|
||||
..lsp::CompletionItem::default()
|
||||
};
|
||||
|
||||
cx.handle_request::<lsp::request::Completion, _, _>(move |_, _, _| {
|
||||
let item1 = item1.clone();
|
||||
cx.handle_request::<lsp::request::Completion, _, _>({
|
||||
let item1 = item1.clone();
|
||||
let item2 = item2.clone();
|
||||
async move { Ok(Some(lsp::CompletionResponse::Array(vec![item1, item2]))) }
|
||||
move |_, _, _| {
|
||||
let item1 = item1.clone();
|
||||
let item2 = item2.clone();
|
||||
async move { Ok(Some(lsp::CompletionResponse::Array(vec![item1, item2]))) }
|
||||
}
|
||||
})
|
||||
.next()
|
||||
.await;
|
||||
@@ -10728,43 +10731,41 @@ async fn test_completions_resolve_updates_labels_if_filter_text_matches(
|
||||
}
|
||||
});
|
||||
|
||||
cx.handle_request::<lsp::request::ResolveCompletionItem, _, _>(move |_, _, _| async move {
|
||||
Ok(lsp::CompletionItem {
|
||||
label: "method id()".to_string(),
|
||||
filter_text: Some("id".to_string()),
|
||||
detail: Some("Now resolved!".to_string()),
|
||||
documentation: Some(lsp::Documentation::String("Docs".to_string())),
|
||||
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
||||
range: lsp::Range::new(lsp::Position::new(0, 22), lsp::Position::new(0, 22)),
|
||||
new_text: ".id".to_string(),
|
||||
})),
|
||||
..lsp::CompletionItem::default()
|
||||
})
|
||||
cx.handle_request::<lsp::request::ResolveCompletionItem, _, _>({
|
||||
let item1 = item1.clone();
|
||||
move |_, item_to_resolve, _| {
|
||||
let item1 = item1.clone();
|
||||
async move {
|
||||
if item1 == item_to_resolve {
|
||||
Ok(lsp::CompletionItem {
|
||||
label: "method id()".to_string(),
|
||||
filter_text: Some("id".to_string()),
|
||||
detail: Some("Now resolved!".to_string()),
|
||||
documentation: Some(lsp::Documentation::String("Docs".to_string())),
|
||||
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
||||
range: lsp::Range::new(
|
||||
lsp::Position::new(0, 22),
|
||||
lsp::Position::new(0, 22),
|
||||
),
|
||||
new_text: ".id".to_string(),
|
||||
})),
|
||||
..lsp::CompletionItem::default()
|
||||
})
|
||||
} else {
|
||||
Ok(item_to_resolve)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.next()
|
||||
.await;
|
||||
.await
|
||||
.unwrap();
|
||||
cx.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.context_menu_next(&Default::default(), cx);
|
||||
});
|
||||
|
||||
cx.handle_request::<lsp::request::ResolveCompletionItem, _, _>(move |_, _, _| async move {
|
||||
Ok(lsp::CompletionItem {
|
||||
label: "invalid changed label".to_string(),
|
||||
detail: Some("Now resolved!".to_string()),
|
||||
documentation: Some(lsp::Documentation::String("Docs".to_string())),
|
||||
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
||||
range: lsp::Range::new(lsp::Position::new(0, 22), lsp::Position::new(0, 22)),
|
||||
new_text: ".id".to_string(),
|
||||
})),
|
||||
..lsp::CompletionItem::default()
|
||||
})
|
||||
})
|
||||
.next()
|
||||
.await;
|
||||
cx.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, _| {
|
||||
let context_menu = editor.context_menu.borrow_mut();
|
||||
let context_menu = context_menu
|
||||
@@ -10787,6 +10788,172 @@ async fn test_completions_resolve_updates_labels_if_filter_text_matches(
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_completions_resolve_happens_once(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
let mut cx = EditorLspTestContext::new_rust(
|
||||
lsp::ServerCapabilities {
|
||||
completion_provider: Some(lsp::CompletionOptions {
|
||||
trigger_characters: Some(vec![".".to_string()]),
|
||||
resolve_provider: Some(true),
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
cx,
|
||||
)
|
||||
.await;
|
||||
|
||||
cx.set_state(indoc! {"fn main() { let a = 2ˇ; }"});
|
||||
cx.simulate_keystroke(".");
|
||||
|
||||
let unresolved_item_1 = lsp::CompletionItem {
|
||||
label: "id".to_string(),
|
||||
filter_text: Some("id".to_string()),
|
||||
detail: None,
|
||||
documentation: None,
|
||||
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
||||
range: lsp::Range::new(lsp::Position::new(0, 22), lsp::Position::new(0, 22)),
|
||||
new_text: ".id".to_string(),
|
||||
})),
|
||||
..lsp::CompletionItem::default()
|
||||
};
|
||||
let resolved_item_1 = lsp::CompletionItem {
|
||||
additional_text_edits: Some(vec![lsp::TextEdit {
|
||||
range: lsp::Range::new(lsp::Position::new(0, 20), lsp::Position::new(0, 22)),
|
||||
new_text: "!!".to_string(),
|
||||
}]),
|
||||
..unresolved_item_1.clone()
|
||||
};
|
||||
let unresolved_item_2 = lsp::CompletionItem {
|
||||
label: "other".to_string(),
|
||||
filter_text: Some("other".to_string()),
|
||||
detail: None,
|
||||
documentation: None,
|
||||
text_edit: Some(lsp::CompletionTextEdit::Edit(lsp::TextEdit {
|
||||
range: lsp::Range::new(lsp::Position::new(0, 22), lsp::Position::new(0, 22)),
|
||||
new_text: ".other".to_string(),
|
||||
})),
|
||||
..lsp::CompletionItem::default()
|
||||
};
|
||||
let resolved_item_2 = lsp::CompletionItem {
|
||||
additional_text_edits: Some(vec![lsp::TextEdit {
|
||||
range: lsp::Range::new(lsp::Position::new(0, 20), lsp::Position::new(0, 22)),
|
||||
new_text: "??".to_string(),
|
||||
}]),
|
||||
..unresolved_item_2.clone()
|
||||
};
|
||||
|
||||
let resolve_requests_1 = Arc::new(AtomicUsize::new(0));
|
||||
let resolve_requests_2 = Arc::new(AtomicUsize::new(0));
|
||||
cx.lsp
|
||||
.server
|
||||
.on_request::<lsp::request::ResolveCompletionItem, _, _>({
|
||||
let unresolved_item_1 = unresolved_item_1.clone();
|
||||
let resolved_item_1 = resolved_item_1.clone();
|
||||
let unresolved_item_2 = unresolved_item_2.clone();
|
||||
let resolved_item_2 = resolved_item_2.clone();
|
||||
let resolve_requests_1 = resolve_requests_1.clone();
|
||||
let resolve_requests_2 = resolve_requests_2.clone();
|
||||
move |unresolved_request, _| {
|
||||
let unresolved_item_1 = unresolved_item_1.clone();
|
||||
let resolved_item_1 = resolved_item_1.clone();
|
||||
let unresolved_item_2 = unresolved_item_2.clone();
|
||||
let resolved_item_2 = resolved_item_2.clone();
|
||||
let resolve_requests_1 = resolve_requests_1.clone();
|
||||
let resolve_requests_2 = resolve_requests_2.clone();
|
||||
async move {
|
||||
if unresolved_request == unresolved_item_1 {
|
||||
resolve_requests_1.fetch_add(1, atomic::Ordering::Release);
|
||||
Ok(resolved_item_1.clone())
|
||||
} else if unresolved_request == unresolved_item_2 {
|
||||
resolve_requests_2.fetch_add(1, atomic::Ordering::Release);
|
||||
Ok(resolved_item_2.clone())
|
||||
} else {
|
||||
panic!("Unexpected completion item {unresolved_request:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.detach();
|
||||
|
||||
cx.handle_request::<lsp::request::Completion, _, _>(move |_, _, _| {
|
||||
let unresolved_item_1 = unresolved_item_1.clone();
|
||||
let unresolved_item_2 = unresolved_item_2.clone();
|
||||
async move {
|
||||
Ok(Some(lsp::CompletionResponse::Array(vec![
|
||||
unresolved_item_1,
|
||||
unresolved_item_2,
|
||||
])))
|
||||
}
|
||||
})
|
||||
.next()
|
||||
.await;
|
||||
|
||||
cx.condition(|editor, _| editor.context_menu_visible())
|
||||
.await;
|
||||
cx.update_editor(|editor, _| {
|
||||
let context_menu = editor.context_menu.borrow_mut();
|
||||
let context_menu = context_menu
|
||||
.as_ref()
|
||||
.expect("Should have the context menu deployed");
|
||||
match context_menu {
|
||||
CodeContextMenu::Completions(completions_menu) => {
|
||||
let completions = completions_menu.completions.borrow_mut();
|
||||
assert_eq!(
|
||||
completions
|
||||
.iter()
|
||||
.map(|completion| &completion.label.text)
|
||||
.collect::<Vec<_>>(),
|
||||
vec!["id", "other"]
|
||||
)
|
||||
}
|
||||
CodeContextMenu::CodeActions(_) => panic!("Should show the completions menu"),
|
||||
}
|
||||
});
|
||||
cx.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.context_menu_next(&ContextMenuNext, cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.context_menu_prev(&ContextMenuPrev, cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.context_menu_next(&ContextMenuNext, cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor
|
||||
.compose_completion(&ComposeCompletion::default(), cx)
|
||||
.expect("No task returned")
|
||||
})
|
||||
.await
|
||||
.expect("Completion failed");
|
||||
cx.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
assert_eq!(
|
||||
resolve_requests_1.load(atomic::Ordering::Acquire),
|
||||
1,
|
||||
"Should always resolve once despite multiple selections"
|
||||
);
|
||||
assert_eq!(
|
||||
resolve_requests_2.load(atomic::Ordering::Acquire),
|
||||
1,
|
||||
"Should always resolve once after multiple selections and applying the completion"
|
||||
);
|
||||
assert_eq!(
|
||||
editor.text(cx),
|
||||
"fn main() { let a = ??.other; }",
|
||||
"Should use resolved data when applying the completion"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_completions_default_resolve_data_handling(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
@@ -10950,15 +11117,10 @@ async fn test_completions_default_resolve_data_handling(cx: &mut gpui::TestAppCo
|
||||
// Completions that have already been resolved are skipped.
|
||||
assert_eq!(
|
||||
*resolved_items.lock(),
|
||||
[
|
||||
// Selected item is always resolved even if it was resolved before.
|
||||
&items_out[items_out.len() - 1..items_out.len()],
|
||||
&items_out[items_out.len() - 16..items_out.len() - 4]
|
||||
]
|
||||
.concat()
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect::<Vec<lsp::CompletionItem>>()
|
||||
items_out[items_out.len() - 16..items_out.len() - 4]
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect::<Vec<lsp::CompletionItem>>()
|
||||
);
|
||||
resolved_items.lock().clear();
|
||||
}
|
||||
@@ -11098,7 +11260,7 @@ async fn test_document_format_with_prettier(cx: &mut gpui::TestAppContext) {
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
Some(tree_sitter_rust::LANGUAGE.into()),
|
||||
Some(tree_sitter_typescript::LANGUAGE_TYPESCRIPT.into()),
|
||||
)));
|
||||
update_test_language_settings(cx, |settings| {
|
||||
settings.defaults.prettier = Some(PrettierSettings {
|
||||
@@ -14570,6 +14732,62 @@ fn test_inline_completion_text_with_deletions(cx: &mut TestAppContext) {
|
||||
}
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_rename_with_duplicate_edits(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
let mut cx = EditorLspTestContext::new_rust(lsp::ServerCapabilities::default(), cx).await;
|
||||
|
||||
cx.set_state(indoc! {"
|
||||
struct Fˇoo {}
|
||||
"});
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
let highlight_range = Point::new(0, 7)..Point::new(0, 10);
|
||||
let highlight_range = highlight_range.to_anchors(&editor.buffer().read(cx).snapshot(cx));
|
||||
editor.highlight_background::<DocumentHighlightRead>(
|
||||
&[highlight_range],
|
||||
|c| c.editor_document_highlight_read_background,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
|
||||
cx.update_editor(|e, cx| e.rename(&Rename, cx))
|
||||
.expect("Rename was not started")
|
||||
.await
|
||||
.expect("Rename failed");
|
||||
let mut rename_handler =
|
||||
cx.handle_request::<lsp::request::Rename, _, _>(move |url, _, _| async move {
|
||||
let edit = lsp::TextEdit {
|
||||
range: lsp::Range {
|
||||
start: lsp::Position {
|
||||
line: 0,
|
||||
character: 7,
|
||||
},
|
||||
end: lsp::Position {
|
||||
line: 0,
|
||||
character: 10,
|
||||
},
|
||||
},
|
||||
new_text: "FooRenamed".to_string(),
|
||||
};
|
||||
Ok(Some(lsp::WorkspaceEdit::new(
|
||||
// Specify the same edit twice
|
||||
std::collections::HashMap::from_iter(Some((url, vec![edit.clone(), edit]))),
|
||||
)))
|
||||
});
|
||||
cx.update_editor(|e, cx| e.confirm_rename(&ConfirmRename, cx))
|
||||
.expect("Confirm rename was not started")
|
||||
.await
|
||||
.expect("Confirm rename failed");
|
||||
rename_handler.next().await.unwrap();
|
||||
cx.run_until_parked();
|
||||
|
||||
// Despite two edits, only one is actually applied as those are identical
|
||||
cx.assert_editor_state(indoc! {"
|
||||
struct FooRenamedˇ {}
|
||||
"});
|
||||
}
|
||||
|
||||
fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
|
||||
let point = DisplayPoint::new(DisplayRow(row as u32), column as u32);
|
||||
point..point
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -266,7 +266,7 @@ pub fn update_inlay_link_and_hover_points(
|
||||
editor: &mut Editor,
|
||||
secondary_held: bool,
|
||||
shift_held: bool,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
let hovered_offset = if point_for_position.column_overshoot_after_line_end == 0 {
|
||||
Some(snapshot.display_point_to_inlay_offset(point_for_position.exact_unclipped, Bias::Left))
|
||||
|
||||
@@ -365,7 +365,7 @@ impl Editor {
|
||||
&mut self,
|
||||
diff_base_buffer: Option<Model<Buffer>>,
|
||||
hunk: &HoveredHunk,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> Option<()> {
|
||||
let buffer = self.buffer.clone();
|
||||
let multi_buffer_snapshot = buffer.read(cx).snapshot(cx);
|
||||
@@ -454,7 +454,7 @@ impl Editor {
|
||||
fn apply_diff_hunks_in_range(
|
||||
&mut self,
|
||||
range: Range<Anchor>,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> Option<()> {
|
||||
let (buffer, range, _) = self
|
||||
.buffer
|
||||
@@ -530,7 +530,7 @@ impl Editor {
|
||||
fn hunk_header_block(
|
||||
&self,
|
||||
hunk: &HoveredHunk,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> BlockProperties<Anchor> {
|
||||
let is_branch_buffer = self
|
||||
.buffer
|
||||
@@ -801,7 +801,7 @@ impl Editor {
|
||||
hunk: &HoveredHunk,
|
||||
diff_base_buffer: Model<Buffer>,
|
||||
deleted_text_height: u32,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> BlockProperties<Anchor> {
|
||||
let gutter_color = match hunk.status {
|
||||
DiffHunkStatus::Added => unreachable!(),
|
||||
@@ -864,7 +864,7 @@ impl Editor {
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn clear_expanded_diff_hunks(&mut self, cx: &mut ViewContext<'_, Editor>) -> bool {
|
||||
pub(super) fn clear_expanded_diff_hunks(&mut self, cx: &mut ViewContext<Editor>) -> bool {
|
||||
if self.diff_map.expand_all {
|
||||
return false;
|
||||
}
|
||||
@@ -887,7 +887,7 @@ impl Editor {
|
||||
pub(super) fn sync_expanded_diff_hunks(
|
||||
diff_map: &mut DiffMap,
|
||||
buffer_id: BufferId,
|
||||
cx: &mut ViewContext<'_, Self>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
let diff_base_state = diff_map.diff_bases.get_mut(&buffer_id);
|
||||
let mut diff_base_buffer = None;
|
||||
@@ -1134,7 +1134,7 @@ fn editor_with_deleted_text(
|
||||
diff_base_buffer: Model<Buffer>,
|
||||
deleted_color: Hsla,
|
||||
hunk: &HoveredHunk,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> (u32, View<Editor>) {
|
||||
let parent_editor = cx.view().downgrade();
|
||||
let editor = cx.new_view(|cx| {
|
||||
|
||||
@@ -579,7 +579,7 @@ impl InlayHintCache {
|
||||
buffer_id: BufferId,
|
||||
excerpt_id: ExcerptId,
|
||||
id: InlayId,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
if let Some(excerpt_hints) = self.hints.get(&excerpt_id) {
|
||||
let mut guard = excerpt_hints.write();
|
||||
@@ -640,7 +640,7 @@ fn spawn_new_update_tasks(
|
||||
excerpts_to_query: HashMap<ExcerptId, (Model<Buffer>, Global, Range<usize>)>,
|
||||
invalidate: InvalidationStrategy,
|
||||
update_cache_version: usize,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
for (excerpt_id, (excerpt_buffer, new_task_buffer_version, excerpt_visible_range)) in
|
||||
excerpts_to_query
|
||||
@@ -797,7 +797,7 @@ fn new_update_task(
|
||||
query: ExcerptQuery,
|
||||
query_ranges: QueryRanges,
|
||||
excerpt_buffer: Model<Buffer>,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> Task<()> {
|
||||
cx.spawn(move |editor, mut cx| async move {
|
||||
let visible_range_update_results = future::join_all(
|
||||
@@ -1129,7 +1129,7 @@ fn apply_hint_update(
|
||||
invalidate: bool,
|
||||
buffer_snapshot: BufferSnapshot,
|
||||
multi_buffer_snapshot: MultiBufferSnapshot,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
let cached_excerpt_hints = editor
|
||||
.inlay_hint_cache
|
||||
@@ -3434,7 +3434,7 @@ pub mod tests {
|
||||
labels
|
||||
}
|
||||
|
||||
pub fn visible_hint_labels(editor: &Editor, cx: &ViewContext<'_, Editor>) -> Vec<String> {
|
||||
pub fn visible_hint_labels(editor: &Editor, cx: &ViewContext<Editor>) -> Vec<String> {
|
||||
let mut hints = editor
|
||||
.visible_inlay_hints(cx)
|
||||
.into_iter()
|
||||
|
||||
@@ -288,7 +288,7 @@ impl EventEmitter<EditorEvent> for ProposedChangesEditor {}
|
||||
impl Item for ProposedChangesEditor {
|
||||
type Event = EditorEvent;
|
||||
|
||||
fn tab_icon(&self, _cx: &ui::WindowContext) -> Option<Icon> {
|
||||
fn tab_icon(&self, _cx: &WindowContext) -> Option<Icon> {
|
||||
Some(Icon::new(IconName::Diff))
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ pub fn apply_related_actions(editor: &View<Editor>, cx: &mut WindowContext) {
|
||||
pub fn expand_macro_recursively(
|
||||
editor: &mut Editor,
|
||||
_: &ExpandMacroRecursively,
|
||||
cx: &mut ViewContext<'_, Editor>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) {
|
||||
if editor.selections.count() == 0 {
|
||||
return;
|
||||
@@ -98,7 +98,7 @@ pub fn expand_macro_recursively(
|
||||
.detach_and_log_err(cx);
|
||||
}
|
||||
|
||||
pub fn open_docs(editor: &mut Editor, _: &OpenDocs, cx: &mut ViewContext<'_, Editor>) {
|
||||
pub fn open_docs(editor: &mut Editor, _: &OpenDocs, cx: &mut ViewContext<Editor>) {
|
||||
if editor.selections.count() == 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ use crate::{
|
||||
ScrollAnchor, ScrollCursorBottom, ScrollCursorCenter, ScrollCursorCenterTopBottom,
|
||||
ScrollCursorTop, SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT,
|
||||
};
|
||||
use gpui::{Point, ViewContext};
|
||||
use gpui::{AsyncWindowContext, Point, ViewContext};
|
||||
|
||||
impl Editor {
|
||||
pub fn next_screen(&mut self, _: &NextScreen, cx: &mut ViewContext<Editor>) {
|
||||
@@ -75,7 +75,7 @@ impl Editor {
|
||||
|
||||
self.next_scroll_position = self.next_scroll_position.next();
|
||||
self._scroll_cursor_center_top_bottom_task =
|
||||
cx.spawn(|editor, mut cx: gpui::AsyncWindowContext| async move {
|
||||
cx.spawn(|editor, mut cx: AsyncWindowContext| async move {
|
||||
cx.background_executor()
|
||||
.timer(SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT)
|
||||
.await;
|
||||
|
||||
@@ -8,7 +8,7 @@ use workspace::Workspace;
|
||||
|
||||
fn task_context_with_editor(
|
||||
editor: &mut Editor,
|
||||
cx: &mut WindowContext<'_>,
|
||||
cx: &mut WindowContext,
|
||||
) -> AsyncTask<Option<TaskContext>> {
|
||||
let Some(project) = editor.project.clone() else {
|
||||
return AsyncTask::ready(None);
|
||||
@@ -74,7 +74,7 @@ fn task_context_with_editor(
|
||||
})
|
||||
}
|
||||
|
||||
pub fn task_context(workspace: &Workspace, cx: &mut WindowContext<'_>) -> AsyncTask<TaskContext> {
|
||||
pub fn task_context(workspace: &Workspace, cx: &mut WindowContext) -> AsyncTask<TaskContext> {
|
||||
let Some(editor) = workspace
|
||||
.active_item(cx)
|
||||
.and_then(|item| item.act_as::<Editor>(cx))
|
||||
|
||||
@@ -843,7 +843,7 @@ impl ExtensionsPage {
|
||||
}
|
||||
}
|
||||
|
||||
fn fetch_extensions_debounced(&mut self, cx: &mut ViewContext<'_, ExtensionsPage>) {
|
||||
fn fetch_extensions_debounced(&mut self, cx: &mut ViewContext<ExtensionsPage>) {
|
||||
self.extension_fetch_task = Some(cx.spawn(|this, mut cx| async move {
|
||||
let search = this
|
||||
.update(&mut cx, |this, cx| this.search_query(cx))
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use client::telemetry;
|
||||
use gpui::Task;
|
||||
use gpui::{Task, WindowContext};
|
||||
use human_bytes::human_bytes;
|
||||
use release_channel::{AppCommitSha, AppVersion, ReleaseChannel};
|
||||
use serde::Serialize;
|
||||
use std::{env, fmt::Display};
|
||||
use sysinfo::{MemoryRefreshKind, RefreshKind, System};
|
||||
use ui::WindowContext;
|
||||
|
||||
#[derive(Clone, Debug, Serialize)]
|
||||
pub struct SystemSpecs {
|
||||
|
||||
@@ -884,7 +884,7 @@ impl FileFinderDelegate {
|
||||
fn lookup_absolute_path(
|
||||
&self,
|
||||
query: FileSearchQuery,
|
||||
cx: &mut ViewContext<'_, Picker<Self>>,
|
||||
cx: &mut ViewContext<Picker<Self>>,
|
||||
) -> Task<()> {
|
||||
cx.spawn(|picker, mut cx| async move {
|
||||
let Some(project) = picker
|
||||
|
||||
@@ -10,6 +10,8 @@ use git::GitHostingProviderRegistry;
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
use ashpd::desktop::trash;
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
use collections::BTreeSet;
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
use smol::process::Command;
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
use std::fs::File;
|
||||
@@ -120,6 +122,17 @@ pub trait Fs: Send + Sync {
|
||||
path: &Path,
|
||||
) -> Result<Pin<Box<dyn Send + Stream<Item = Result<PathBuf>>>>>;
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
async fn watch(
|
||||
&self,
|
||||
path: &Path,
|
||||
latency: Duration,
|
||||
) -> (
|
||||
Pin<Box<dyn Send + Stream<Item = BTreeSet<PathEvent>>>>,
|
||||
Arc<dyn Watcher>,
|
||||
);
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
|
||||
async fn watch(
|
||||
&self,
|
||||
path: &Path,
|
||||
@@ -701,13 +714,14 @@ impl Fs for RealFs {
|
||||
path: &Path,
|
||||
latency: Duration,
|
||||
) -> (
|
||||
Pin<Box<dyn Send + Stream<Item = Vec<PathEvent>>>>,
|
||||
Pin<Box<dyn Send + Stream<Item = BTreeSet<PathEvent>>>>,
|
||||
Arc<dyn Watcher>,
|
||||
) {
|
||||
use collections::BTreeSet;
|
||||
use parking_lot::Mutex;
|
||||
|
||||
let (tx, rx) = smol::channel::unbounded();
|
||||
let pending_paths: Arc<Mutex<Vec<PathEvent>>> = Default::default();
|
||||
let pending_paths: Arc<Mutex<BTreeSet<PathEvent>>> = Default::default();
|
||||
let watcher = Arc::new(linux_watcher::LinuxWatcher::new(tx, pending_paths.clone()));
|
||||
|
||||
if watcher.add(path).is_err() {
|
||||
@@ -1938,6 +1952,7 @@ impl Fs for FakeFs {
|
||||
Ok(Box::pin(futures::stream::iter(paths)))
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
|
||||
async fn watch(
|
||||
&self,
|
||||
path: &Path,
|
||||
@@ -1966,6 +1981,38 @@ impl Fs for FakeFs {
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
|
||||
async fn watch(
|
||||
&self,
|
||||
path: &Path,
|
||||
_: Duration,
|
||||
) -> (
|
||||
Pin<Box<dyn Send + Stream<Item = BTreeSet<PathEvent>>>>,
|
||||
Arc<dyn Watcher>,
|
||||
) {
|
||||
self.simulate_random_delay().await;
|
||||
let (tx, rx) = smol::channel::unbounded();
|
||||
self.state.lock().event_txs.push(tx);
|
||||
let path = path.to_path_buf();
|
||||
let executor = self.executor.clone();
|
||||
(
|
||||
Box::pin(
|
||||
futures::StreamExt::filter(rx, move |events| {
|
||||
let result = events
|
||||
.iter()
|
||||
.any(|evt_path| evt_path.path.starts_with(&path));
|
||||
let executor = executor.clone();
|
||||
async move {
|
||||
executor.simulate_random_delay().await;
|
||||
result
|
||||
}
|
||||
})
|
||||
.map(|events| BTreeSet::from_iter(events.into_iter())),
|
||||
),
|
||||
Arc::new(FakeWatcher {}),
|
||||
)
|
||||
}
|
||||
|
||||
fn open_repo(&self, abs_dot_git: &Path) -> Option<Arc<dyn GitRepository>> {
|
||||
let state = self.state.lock();
|
||||
let entry = state.read_path(abs_dot_git).unwrap();
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use collections::BTreeSet;
|
||||
use notify::EventKind;
|
||||
use parking_lot::Mutex;
|
||||
use std::sync::{Arc, OnceLock};
|
||||
@@ -7,13 +8,13 @@ use crate::{PathEvent, PathEventKind, Watcher};
|
||||
|
||||
pub struct LinuxWatcher {
|
||||
tx: smol::channel::Sender<()>,
|
||||
pending_path_events: Arc<Mutex<Vec<PathEvent>>>,
|
||||
pending_path_events: Arc<Mutex<BTreeSet<PathEvent>>>,
|
||||
}
|
||||
|
||||
impl LinuxWatcher {
|
||||
pub fn new(
|
||||
tx: smol::channel::Sender<()>,
|
||||
pending_path_events: Arc<Mutex<Vec<PathEvent>>>,
|
||||
pending_path_events: Arc<Mutex<BTreeSet<PathEvent>>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
tx,
|
||||
@@ -40,7 +41,7 @@ impl Watcher for LinuxWatcher {
|
||||
EventKind::Remove(_) => Some(PathEventKind::Removed),
|
||||
_ => None,
|
||||
};
|
||||
let mut path_events = event
|
||||
let path_events = event
|
||||
.paths
|
||||
.iter()
|
||||
.filter_map(|event_path| {
|
||||
@@ -52,17 +53,12 @@ impl Watcher for LinuxWatcher {
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !path_events.is_empty() {
|
||||
path_events.sort();
|
||||
let mut pending_paths = pending_paths.lock();
|
||||
if pending_paths.is_empty() {
|
||||
let was_empty = pending_paths.is_empty();
|
||||
pending_paths.extend(path_events);
|
||||
if was_empty {
|
||||
tx.try_send(()).ok();
|
||||
}
|
||||
util::extend_sorted(
|
||||
&mut *pending_paths,
|
||||
path_events,
|
||||
usize::MAX,
|
||||
|a, b| a.path.cmp(&b.path),
|
||||
);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ pub struct Matcher<'a> {
|
||||
lowercase_query: &'a [char],
|
||||
query_char_bag: CharBag,
|
||||
smart_case: bool,
|
||||
max_results: usize,
|
||||
min_score: f64,
|
||||
match_positions: Vec<usize>,
|
||||
last_positions: Vec<usize>,
|
||||
@@ -22,11 +21,6 @@ pub struct Matcher<'a> {
|
||||
best_position_matrix: Vec<usize>,
|
||||
}
|
||||
|
||||
pub trait Match: Ord {
|
||||
fn score(&self) -> f64;
|
||||
fn set_positions(&mut self, positions: Vec<usize>);
|
||||
}
|
||||
|
||||
pub trait MatchCandidate {
|
||||
fn has_chars(&self, bag: CharBag) -> bool;
|
||||
fn to_string(&self) -> Cow<'_, str>;
|
||||
@@ -38,7 +32,6 @@ impl<'a> Matcher<'a> {
|
||||
lowercase_query: &'a [char],
|
||||
query_char_bag: CharBag,
|
||||
smart_case: bool,
|
||||
max_results: usize,
|
||||
) -> Self {
|
||||
Self {
|
||||
query,
|
||||
@@ -50,10 +43,11 @@ impl<'a> Matcher<'a> {
|
||||
score_matrix: Vec::new(),
|
||||
best_position_matrix: Vec::new(),
|
||||
smart_case,
|
||||
max_results,
|
||||
}
|
||||
}
|
||||
|
||||
/// Filter and score fuzzy match candidates. Results are returned unsorted, in the same order as
|
||||
/// the input candidates.
|
||||
pub fn match_candidates<C: MatchCandidate, R, F>(
|
||||
&mut self,
|
||||
prefix: &[char],
|
||||
@@ -63,8 +57,7 @@ impl<'a> Matcher<'a> {
|
||||
cancel_flag: &AtomicBool,
|
||||
build_match: F,
|
||||
) where
|
||||
R: Match,
|
||||
F: Fn(&C, f64) -> R,
|
||||
F: Fn(&C, f64, &Vec<usize>) -> R,
|
||||
{
|
||||
let mut candidate_chars = Vec::new();
|
||||
let mut lowercase_candidate_chars = Vec::new();
|
||||
@@ -103,20 +96,7 @@ impl<'a> Matcher<'a> {
|
||||
);
|
||||
|
||||
if score > 0.0 {
|
||||
let mut mat = build_match(&candidate, score);
|
||||
if let Err(i) = results.binary_search_by(|m| mat.cmp(m)) {
|
||||
if results.len() < self.max_results {
|
||||
mat.set_positions(self.match_positions.clone());
|
||||
results.insert(i, mat);
|
||||
} else if i < results.len() {
|
||||
results.pop();
|
||||
mat.set_positions(self.match_positions.clone());
|
||||
results.insert(i, mat);
|
||||
}
|
||||
if results.len() == self.max_results {
|
||||
self.min_score = results.last().unwrap().score();
|
||||
}
|
||||
}
|
||||
results.push(build_match(&candidate, score, &self.match_positions));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -325,18 +305,18 @@ mod tests {
|
||||
#[test]
|
||||
fn test_get_last_positions() {
|
||||
let mut query: &[char] = &['d', 'c'];
|
||||
let mut matcher = Matcher::new(query, query, query.into(), false, 10);
|
||||
let mut matcher = Matcher::new(query, query, query.into(), false);
|
||||
let result = matcher.find_last_positions(&['a', 'b', 'c'], &['b', 'd', 'e', 'f']);
|
||||
assert!(!result);
|
||||
|
||||
query = &['c', 'd'];
|
||||
let mut matcher = Matcher::new(query, query, query.into(), false, 10);
|
||||
let mut matcher = Matcher::new(query, query, query.into(), false);
|
||||
let result = matcher.find_last_positions(&['a', 'b', 'c'], &['b', 'd', 'e', 'f']);
|
||||
assert!(result);
|
||||
assert_eq!(matcher.last_positions, vec![2, 4]);
|
||||
|
||||
query = &['z', '/', 'z', 'f'];
|
||||
let mut matcher = Matcher::new(query, query, query.into(), false, 10);
|
||||
let mut matcher = Matcher::new(query, query, query.into(), false);
|
||||
let result = matcher.find_last_positions(&['z', 'e', 'd', '/'], &['z', 'e', 'd', '/', 'f']);
|
||||
assert!(result);
|
||||
assert_eq!(matcher.last_positions, vec![0, 3, 4, 8]);
|
||||
@@ -451,7 +431,7 @@ mod tests {
|
||||
});
|
||||
}
|
||||
|
||||
let mut matcher = Matcher::new(&query, &lowercase_query, query_chars, smart_case, 100);
|
||||
let mut matcher = Matcher::new(&query, &lowercase_query, query_chars, smart_case);
|
||||
|
||||
let cancel_flag = AtomicBool::new(false);
|
||||
let mut results = Vec::new();
|
||||
@@ -462,16 +442,17 @@ mod tests {
|
||||
path_entries.into_iter(),
|
||||
&mut results,
|
||||
&cancel_flag,
|
||||
|candidate, score| PathMatch {
|
||||
|candidate, score, positions| PathMatch {
|
||||
score,
|
||||
worktree_id: 0,
|
||||
positions: Vec::new(),
|
||||
positions: positions.clone(),
|
||||
path: Arc::from(candidate.path),
|
||||
path_prefix: "".into(),
|
||||
distance_to_relative_ancestor: usize::MAX,
|
||||
is_dir: false,
|
||||
},
|
||||
);
|
||||
results.sort_by(|a, b| b.cmp(a));
|
||||
|
||||
results
|
||||
.into_iter()
|
||||
|
||||
@@ -7,7 +7,7 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
matcher::{Match, MatchCandidate, Matcher},
|
||||
matcher::{MatchCandidate, Matcher},
|
||||
CharBag,
|
||||
};
|
||||
|
||||
@@ -42,16 +42,6 @@ pub trait PathMatchCandidateSet<'a>: Send + Sync {
|
||||
fn candidates(&'a self, start: usize) -> Self::Candidates;
|
||||
}
|
||||
|
||||
impl Match for PathMatch {
|
||||
fn score(&self) -> f64 {
|
||||
self.score
|
||||
}
|
||||
|
||||
fn set_positions(&mut self, positions: Vec<usize>) {
|
||||
self.positions = positions;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MatchCandidate for PathMatchCandidate<'a> {
|
||||
fn has_chars(&self, bag: CharBag) -> bool {
|
||||
self.char_bag.is_superset(bag)
|
||||
@@ -102,13 +92,7 @@ pub fn match_fixed_path_set(
|
||||
let query = query.chars().collect::<Vec<_>>();
|
||||
let query_char_bag = CharBag::from(&lowercase_query[..]);
|
||||
|
||||
let mut matcher = Matcher::new(
|
||||
&query,
|
||||
&lowercase_query,
|
||||
query_char_bag,
|
||||
smart_case,
|
||||
max_results,
|
||||
);
|
||||
let mut matcher = Matcher::new(&query, &lowercase_query, query_char_bag, smart_case);
|
||||
|
||||
let mut results = Vec::new();
|
||||
matcher.match_candidates(
|
||||
@@ -117,16 +101,17 @@ pub fn match_fixed_path_set(
|
||||
candidates.into_iter(),
|
||||
&mut results,
|
||||
&AtomicBool::new(false),
|
||||
|candidate, score| PathMatch {
|
||||
|candidate, score, positions| PathMatch {
|
||||
score,
|
||||
worktree_id,
|
||||
positions: Vec::new(),
|
||||
positions: positions.clone(),
|
||||
is_dir: candidate.is_dir,
|
||||
path: Arc::from(candidate.path),
|
||||
path_prefix: Arc::default(),
|
||||
distance_to_relative_ancestor: usize::MAX,
|
||||
},
|
||||
);
|
||||
util::truncate_to_bottom_n_sorted_by(&mut results, max_results, &|a, b| b.cmp(a));
|
||||
results
|
||||
}
|
||||
|
||||
@@ -164,13 +149,8 @@ pub async fn match_path_sets<'a, Set: PathMatchCandidateSet<'a>>(
|
||||
scope.spawn(async move {
|
||||
let segment_start = segment_idx * segment_size;
|
||||
let segment_end = segment_start + segment_size;
|
||||
let mut matcher = Matcher::new(
|
||||
query,
|
||||
lowercase_query,
|
||||
query_char_bag,
|
||||
smart_case,
|
||||
max_results,
|
||||
);
|
||||
let mut matcher =
|
||||
Matcher::new(query, lowercase_query, query_char_bag, smart_case);
|
||||
|
||||
let mut tree_start = 0;
|
||||
for candidate_set in candidate_sets {
|
||||
@@ -193,10 +173,10 @@ pub async fn match_path_sets<'a, Set: PathMatchCandidateSet<'a>>(
|
||||
candidates,
|
||||
results,
|
||||
cancel_flag,
|
||||
|candidate, score| PathMatch {
|
||||
|candidate, score, positions| PathMatch {
|
||||
score,
|
||||
worktree_id,
|
||||
positions: Vec::new(),
|
||||
positions: positions.clone(),
|
||||
path: Arc::from(candidate.path),
|
||||
is_dir: candidate.is_dir,
|
||||
path_prefix: candidate_set.prefix(),
|
||||
@@ -222,14 +202,8 @@ pub async fn match_path_sets<'a, Set: PathMatchCandidateSet<'a>>(
|
||||
})
|
||||
.await;
|
||||
|
||||
let mut results = Vec::new();
|
||||
for segment_result in segment_results {
|
||||
if results.is_empty() {
|
||||
results = segment_result;
|
||||
} else {
|
||||
util::extend_sorted(&mut results, segment_result, max_results, |a, b| b.cmp(a));
|
||||
}
|
||||
}
|
||||
let mut results = segment_results.concat();
|
||||
util::truncate_to_bottom_n_sorted_by(&mut results, max_results, &|a, b| b.cmp(a));
|
||||
results
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
matcher::{Match, MatchCandidate, Matcher},
|
||||
matcher::{MatchCandidate, Matcher},
|
||||
CharBag,
|
||||
};
|
||||
use gpui::BackgroundExecutor;
|
||||
@@ -46,16 +46,6 @@ pub struct StringMatch {
|
||||
pub string: String,
|
||||
}
|
||||
|
||||
impl Match for StringMatch {
|
||||
fn score(&self) -> f64 {
|
||||
self.score
|
||||
}
|
||||
|
||||
fn set_positions(&mut self, positions: Vec<usize>) {
|
||||
self.positions = positions;
|
||||
}
|
||||
}
|
||||
|
||||
impl StringMatch {
|
||||
pub fn ranges(&self) -> impl '_ + Iterator<Item = Range<usize>> {
|
||||
let mut positions = self.positions.iter().peekable();
|
||||
@@ -167,13 +157,8 @@ pub async fn match_strings(
|
||||
scope.spawn(async move {
|
||||
let segment_start = cmp::min(segment_idx * segment_size, candidates.len());
|
||||
let segment_end = cmp::min(segment_start + segment_size, candidates.len());
|
||||
let mut matcher = Matcher::new(
|
||||
query,
|
||||
lowercase_query,
|
||||
query_char_bag,
|
||||
smart_case,
|
||||
max_results,
|
||||
);
|
||||
let mut matcher =
|
||||
Matcher::new(query, lowercase_query, query_char_bag, smart_case);
|
||||
|
||||
matcher.match_candidates(
|
||||
&[],
|
||||
@@ -181,10 +166,10 @@ pub async fn match_strings(
|
||||
candidates[segment_start..segment_end].iter(),
|
||||
results,
|
||||
cancel_flag,
|
||||
|candidate, score| StringMatch {
|
||||
|candidate, score, positions| StringMatch {
|
||||
candidate_id: candidate.id,
|
||||
score,
|
||||
positions: Vec::new(),
|
||||
positions: positions.clone(),
|
||||
string: candidate.string.to_string(),
|
||||
},
|
||||
);
|
||||
@@ -193,13 +178,7 @@ pub async fn match_strings(
|
||||
})
|
||||
.await;
|
||||
|
||||
let mut results = Vec::new();
|
||||
for segment_result in segment_results {
|
||||
if results.is_empty() {
|
||||
results = segment_result;
|
||||
} else {
|
||||
util::extend_sorted(&mut results, segment_result, max_results, |a, b| b.cmp(a));
|
||||
}
|
||||
}
|
||||
let mut results = segment_results.concat();
|
||||
util::truncate_to_bottom_n_sorted_by(&mut results, max_results, &|a, b| b.cmp(a));
|
||||
results
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ pub struct GitPanel {
|
||||
// not hidden by folding or such
|
||||
visible_entries: Vec<WorktreeEntries>,
|
||||
width: Option<Pixels>,
|
||||
git_diff_editor: View<Editor>,
|
||||
git_diff_editor: Option<View<Editor>>,
|
||||
git_diff_editor_updates: Task<()>,
|
||||
reveal_in_editor: Task<()>,
|
||||
}
|
||||
@@ -149,11 +149,7 @@ impl GitPanel {
|
||||
workspace: WeakView<Workspace>,
|
||||
cx: AsyncWindowContext,
|
||||
) -> Task<Result<View<Self>>> {
|
||||
cx.spawn(|mut cx| async move {
|
||||
// Clippy incorrectly classifies this as a redundant closure
|
||||
#[allow(clippy::redundant_closure)]
|
||||
workspace.update(&mut cx, |workspace, cx| Self::new(workspace, cx))
|
||||
})
|
||||
cx.spawn(|mut cx| async move { workspace.update(&mut cx, Self::new) })
|
||||
}
|
||||
|
||||
pub fn new(workspace: &mut Workspace, cx: &mut ViewContext<Workspace>) -> View<Self> {
|
||||
@@ -168,7 +164,7 @@ impl GitPanel {
|
||||
this.hide_scrollbar(cx);
|
||||
})
|
||||
.detach();
|
||||
cx.subscribe(&project, |this, project, event, cx| match event {
|
||||
cx.subscribe(&project, |this, _, event, cx| match event {
|
||||
project::Event::WorktreeRemoved(id) => {
|
||||
this.expanded_dir_ids.remove(id);
|
||||
this.update_visible_entries(None, None, cx);
|
||||
@@ -186,9 +182,10 @@ impl GitPanel {
|
||||
}
|
||||
project::Event::Closed => {
|
||||
this.git_diff_editor_updates = Task::ready(());
|
||||
this.reveal_in_editor = Task::ready(());
|
||||
this.expanded_dir_ids.clear();
|
||||
this.visible_entries.clear();
|
||||
this.git_diff_editor = diff_display_editor(project.clone(), cx);
|
||||
this.git_diff_editor = None;
|
||||
}
|
||||
_ => {}
|
||||
})
|
||||
@@ -196,7 +193,7 @@ impl GitPanel {
|
||||
|
||||
let scroll_handle = UniformListScrollHandle::new();
|
||||
|
||||
let mut this = Self {
|
||||
let mut git_panel = Self {
|
||||
workspace: weak_workspace,
|
||||
focus_handle: cx.focus_handle(),
|
||||
fs,
|
||||
@@ -211,13 +208,13 @@ impl GitPanel {
|
||||
selected_item: None,
|
||||
show_scrollbar: !Self::should_autohide_scrollbar(cx),
|
||||
hide_scrollbar_task: None,
|
||||
git_diff_editor: diff_display_editor(project.clone(), cx),
|
||||
git_diff_editor: Some(diff_display_editor(cx)),
|
||||
git_diff_editor_updates: Task::ready(()),
|
||||
reveal_in_editor: Task::ready(()),
|
||||
project,
|
||||
};
|
||||
this.update_visible_entries(None, None, cx);
|
||||
this
|
||||
git_panel.update_visible_entries(None, None, cx);
|
||||
git_panel
|
||||
});
|
||||
|
||||
git_panel
|
||||
@@ -602,7 +599,7 @@ impl GitPanel {
|
||||
);
|
||||
}
|
||||
|
||||
let project = self.project.clone();
|
||||
let project = self.project.downgrade();
|
||||
self.git_diff_editor_updates = cx.spawn(|git_panel, mut cx| async move {
|
||||
cx.background_executor()
|
||||
.timer(UPDATE_DEBOUNCE)
|
||||
@@ -610,7 +607,7 @@ impl GitPanel {
|
||||
let Some(project_buffers) = git_panel
|
||||
.update(&mut cx, |git_panel, cx| {
|
||||
futures::future::join_all(git_panel.visible_entries.iter_mut().flat_map(
|
||||
move |worktree_entries| {
|
||||
|worktree_entries| {
|
||||
worktree_entries
|
||||
.visible_entries
|
||||
.iter()
|
||||
@@ -694,7 +691,7 @@ impl GitPanel {
|
||||
anyhow::Ok((buffer, unstaged_changes, hunks))
|
||||
});
|
||||
Some((entry_path, unstaged_changes_task))
|
||||
})?;
|
||||
}).ok()??;
|
||||
Some((entry_path, unstaged_changes_task))
|
||||
})
|
||||
.map(|(entry_path, open_task)| async move {
|
||||
@@ -716,7 +713,7 @@ impl GitPanel {
|
||||
let mut change_sets = Vec::with_capacity(project_buffers.len());
|
||||
if let Some(buffer_update_task) = git_panel
|
||||
.update(&mut cx, |git_panel, cx| {
|
||||
let editor = git_panel.git_diff_editor.clone();
|
||||
let editor = git_panel.git_diff_editor.clone()?;
|
||||
let multi_buffer = editor.read(cx).buffer().clone();
|
||||
let mut buffers_with_ranges = Vec::with_capacity(project_buffers.len());
|
||||
for (buffer_path, open_result) in project_buffers {
|
||||
@@ -735,25 +732,27 @@ impl GitPanel {
|
||||
}
|
||||
}
|
||||
|
||||
multi_buffer.update(cx, |multi_buffer, cx| {
|
||||
Some(multi_buffer.update(cx, |multi_buffer, cx| {
|
||||
multi_buffer.clear(cx);
|
||||
multi_buffer.push_multiple_excerpts_with_context_lines(
|
||||
buffers_with_ranges,
|
||||
DEFAULT_MULTIBUFFER_CONTEXT,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
}))
|
||||
})
|
||||
.ok()
|
||||
.ok().flatten()
|
||||
{
|
||||
buffer_update_task.await;
|
||||
git_panel
|
||||
.update(&mut cx, |git_panel, cx| {
|
||||
git_panel.git_diff_editor.update(cx, |editor, cx| {
|
||||
for change_set in change_sets {
|
||||
editor.add_change_set(change_set, cx);
|
||||
}
|
||||
})
|
||||
if let Some(diff_editor) = git_panel.git_diff_editor.as_ref() {
|
||||
diff_editor.update(cx, |editor, cx| {
|
||||
for change_set in change_sets {
|
||||
editor.add_change_set(change_set, cx);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
@@ -1001,7 +1000,7 @@ impl GitPanel {
|
||||
let id = id.to_proto() as usize;
|
||||
let checkbox_id = ElementId::Name(format!("checkbox_{}", id).into());
|
||||
let is_staged = ToggleState::Selected;
|
||||
let handle = cx.view().clone();
|
||||
let handle = cx.view().downgrade();
|
||||
|
||||
h_flex()
|
||||
.id(id)
|
||||
@@ -1024,16 +1023,18 @@ impl GitPanel {
|
||||
.toggle_state(selected)
|
||||
.child(h_flex().gap_1p5().child(details.display_name.clone()))
|
||||
.on_click(move |e, cx| {
|
||||
handle.update(cx, |git_panel, cx| {
|
||||
git_panel.selected_item = Some(details.index);
|
||||
let change_focus = e.down.click_count > 1;
|
||||
git_panel.reveal_entry_in_git_editor(
|
||||
details.hunks.clone(),
|
||||
change_focus,
|
||||
None,
|
||||
cx,
|
||||
);
|
||||
});
|
||||
handle
|
||||
.update(cx, |git_panel, cx| {
|
||||
git_panel.selected_item = Some(details.index);
|
||||
let change_focus = e.down.click_count > 1;
|
||||
git_panel.reveal_entry_in_git_editor(
|
||||
details.hunks.clone(),
|
||||
change_focus,
|
||||
None,
|
||||
cx,
|
||||
);
|
||||
})
|
||||
.ok();
|
||||
}),
|
||||
)
|
||||
}
|
||||
@@ -1043,10 +1044,12 @@ impl GitPanel {
|
||||
hunks: Rc<OnceCell<Vec<DiffHunk>>>,
|
||||
change_focus: bool,
|
||||
debounce: Option<Duration>,
|
||||
cx: &mut ViewContext<'_, Self>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
let workspace = self.workspace.clone();
|
||||
let diff_editor = self.git_diff_editor.clone();
|
||||
let Some(diff_editor) = self.git_diff_editor.clone() else {
|
||||
return;
|
||||
};
|
||||
self.reveal_in_editor = cx.spawn(|_, mut cx| async move {
|
||||
if let Some(debounce) = debounce {
|
||||
cx.background_executor().timer(debounce).await;
|
||||
@@ -1196,7 +1199,7 @@ impl Panel for GitPanel {
|
||||
"GitPanel"
|
||||
}
|
||||
|
||||
fn position(&self, cx: &gpui::WindowContext) -> DockPosition {
|
||||
fn position(&self, cx: &WindowContext) -> DockPosition {
|
||||
GitPanelSettings::get_global(cx).dock
|
||||
}
|
||||
|
||||
@@ -1212,7 +1215,7 @@ impl Panel for GitPanel {
|
||||
);
|
||||
}
|
||||
|
||||
fn size(&self, cx: &gpui::WindowContext) -> Pixels {
|
||||
fn size(&self, cx: &WindowContext) -> Pixels {
|
||||
self.width
|
||||
.unwrap_or_else(|| GitPanelSettings::get_global(cx).default_width)
|
||||
}
|
||||
@@ -1234,14 +1237,18 @@ impl Panel for GitPanel {
|
||||
fn toggle_action(&self) -> Box<dyn Action> {
|
||||
Box::new(ToggleFocus)
|
||||
}
|
||||
|
||||
fn activation_priority(&self) -> u32 {
|
||||
2
|
||||
}
|
||||
}
|
||||
|
||||
fn diff_display_editor(project: Model<Project>, cx: &mut WindowContext) -> View<Editor> {
|
||||
fn diff_display_editor(cx: &mut WindowContext) -> View<Editor> {
|
||||
cx.new_view(|cx| {
|
||||
let multi_buffer = cx.new_model(|cx| {
|
||||
MultiBuffer::new(project.read(cx).capability()).with_title("Project diff".to_string())
|
||||
let multi_buffer = cx.new_model(|_| {
|
||||
MultiBuffer::new(language::Capability::ReadWrite).with_title("Project diff".to_string())
|
||||
});
|
||||
let mut editor = Editor::for_multibuffer(multi_buffer, Some(project), true, cx);
|
||||
let mut editor = Editor::for_multibuffer(multi_buffer, None, true, cx);
|
||||
editor.set_expand_all_diff_hunks();
|
||||
editor
|
||||
})
|
||||
|
||||
@@ -22,7 +22,7 @@ test-support = [
|
||||
"x11",
|
||||
]
|
||||
runtime_shaders = []
|
||||
macos-blade = ["blade-graphics", "blade-macros", "blade-util", "bytemuck"]
|
||||
macos-blade = ["blade-graphics", "blade-macros", "blade-util", "bytemuck", "objc2", "objc2-metal"]
|
||||
wayland = [
|
||||
"blade-graphics",
|
||||
"blade-macros",
|
||||
@@ -132,11 +132,14 @@ core-foundation.workspace = true
|
||||
core-foundation-sys = "0.8"
|
||||
core-graphics = "0.23"
|
||||
core-text = "20.1"
|
||||
font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "40391b7", optional = true}
|
||||
font-kit = { git = "https://github.com/zed-industries/font-kit", rev = "40391b7", optional = true }
|
||||
foreign-types = "0.5"
|
||||
log.workspace = true
|
||||
media.workspace = true
|
||||
objc = "0.2"
|
||||
objc2 = { version = "0.5", optional = true }
|
||||
objc2-metal = { version = "0.2", optional = true }
|
||||
#TODO: replace with "objc2"
|
||||
metal.workspace = true
|
||||
|
||||
[target.'cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))'.dependencies]
|
||||
|
||||
@@ -1,25 +1,574 @@
|
||||
use gpui::{
|
||||
div, prelude::*, px, rgb, size, App, AppContext, Bounds, ViewContext, WindowBounds,
|
||||
WindowOptions,
|
||||
div, hsla, point, prelude::*, px, relative, rgb, size, App, AppContext, Bounds, BoxShadow, Div,
|
||||
SharedString, ViewContext, WindowBounds, WindowOptions,
|
||||
};
|
||||
|
||||
use smallvec::smallvec;
|
||||
|
||||
struct Shadow {}
|
||||
|
||||
impl Shadow {
|
||||
fn base() -> Div {
|
||||
div()
|
||||
.size_16()
|
||||
.bg(rgb(0xffffff))
|
||||
.rounded_full()
|
||||
.border_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 0.1))
|
||||
}
|
||||
|
||||
fn square() -> Div {
|
||||
div()
|
||||
.size_16()
|
||||
.bg(rgb(0xffffff))
|
||||
.border_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 0.1))
|
||||
}
|
||||
|
||||
fn rounded_small() -> Div {
|
||||
div()
|
||||
.size_16()
|
||||
.bg(rgb(0xffffff))
|
||||
.rounded(px(4.))
|
||||
.border_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 0.1))
|
||||
}
|
||||
|
||||
fn rounded_medium() -> Div {
|
||||
div()
|
||||
.size_16()
|
||||
.bg(rgb(0xffffff))
|
||||
.rounded(px(8.))
|
||||
.border_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 0.1))
|
||||
}
|
||||
|
||||
fn rounded_large() -> Div {
|
||||
div()
|
||||
.size_16()
|
||||
.bg(rgb(0xffffff))
|
||||
.rounded(px(12.))
|
||||
.border_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 0.1))
|
||||
}
|
||||
}
|
||||
|
||||
fn example(label: impl Into<SharedString>, example: impl IntoElement) -> impl IntoElement {
|
||||
let label = label.into();
|
||||
|
||||
div()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.justify_center()
|
||||
.items_center()
|
||||
.w(relative(1. / 6.))
|
||||
.border_r_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_center()
|
||||
.flex_1()
|
||||
.py_12()
|
||||
.child(example),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.w_full()
|
||||
.border_t_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
|
||||
.p_1()
|
||||
.flex()
|
||||
.items_center()
|
||||
.child(label),
|
||||
)
|
||||
}
|
||||
|
||||
impl Render for Shadow {
|
||||
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
div()
|
||||
.flex()
|
||||
.id("shadow-example")
|
||||
.overflow_y_scroll()
|
||||
.bg(rgb(0xffffff))
|
||||
.size_full()
|
||||
.justify_center()
|
||||
.items_center()
|
||||
.child(div().size_8().shadow_sm())
|
||||
.text_xs()
|
||||
.child(div().flex().flex_col().w_full().children(vec![
|
||||
div()
|
||||
.border_b_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
|
||||
.flex()
|
||||
.flex_row()
|
||||
.children(vec![
|
||||
example(
|
||||
"Square",
|
||||
Shadow::square()
|
||||
.shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Rounded 4",
|
||||
Shadow::rounded_small()
|
||||
.shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Rounded 8",
|
||||
Shadow::rounded_medium()
|
||||
.shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Rounded 16",
|
||||
Shadow::rounded_large()
|
||||
.shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Circle",
|
||||
Shadow::base()
|
||||
.shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
]),
|
||||
div()
|
||||
.border_b_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
|
||||
.flex()
|
||||
.w_full()
|
||||
.children(vec![
|
||||
example("None", Shadow::base()),
|
||||
// Small shadow
|
||||
example("Small", Shadow::base().shadow_sm()),
|
||||
// Medium shadow
|
||||
example("Medium", Shadow::base().shadow_md()),
|
||||
// Large shadow
|
||||
example("Large", Shadow::base().shadow_lg()),
|
||||
example("Extra Large", Shadow::base().shadow_xl()),
|
||||
example("2X Large", Shadow::base().shadow_2xl()),
|
||||
]),
|
||||
// Horizontal list of increasing blur radii
|
||||
div()
|
||||
.border_b_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
|
||||
.flex()
|
||||
.children(vec![
|
||||
example(
|
||||
"Blur 0",
|
||||
Shadow::base().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(0.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Blur 2",
|
||||
Shadow::base().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(2.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Blur 4",
|
||||
Shadow::base().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(4.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Blur 8",
|
||||
Shadow::base().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Blur 16",
|
||||
Shadow::base().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(16.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
]),
|
||||
// Horizontal list of increasing spread radii
|
||||
div()
|
||||
.border_b_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
|
||||
.flex()
|
||||
.children(vec![
|
||||
example(
|
||||
"Spread 0",
|
||||
Shadow::base().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Spread 2",
|
||||
Shadow::base().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(2.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Spread 4",
|
||||
Shadow::base().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(4.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Spread 8",
|
||||
Shadow::base().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(8.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Spread 16",
|
||||
Shadow::base().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(16.),
|
||||
}]),
|
||||
),
|
||||
]),
|
||||
// Square spread examples
|
||||
div()
|
||||
.border_b_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
|
||||
.flex()
|
||||
.children(vec![
|
||||
example(
|
||||
"Square Spread 0",
|
||||
Shadow::square().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Square Spread 8",
|
||||
Shadow::square().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(8.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Square Spread 16",
|
||||
Shadow::square().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(16.),
|
||||
}]),
|
||||
),
|
||||
]),
|
||||
// Rounded large spread examples
|
||||
div()
|
||||
.border_b_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
|
||||
.flex()
|
||||
.children(vec![
|
||||
example(
|
||||
"Rounded Large Spread 0",
|
||||
Shadow::rounded_large().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Rounded Large Spread 8",
|
||||
Shadow::rounded_large().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(8.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Rounded Large Spread 16",
|
||||
Shadow::rounded_large().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.0, 0.0, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(16.),
|
||||
}]),
|
||||
),
|
||||
]),
|
||||
// Directional shadows
|
||||
div()
|
||||
.border_b_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
|
||||
.flex()
|
||||
.children(vec![
|
||||
example(
|
||||
"Left",
|
||||
Shadow::base().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(-8.), px(0.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Right",
|
||||
Shadow::base().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(8.), px(0.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Top",
|
||||
Shadow::base().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(0.), px(-8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Bottom",
|
||||
Shadow::base().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
]),
|
||||
// Square directional shadows
|
||||
div()
|
||||
.border_b_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
|
||||
.flex()
|
||||
.children(vec![
|
||||
example(
|
||||
"Square Left",
|
||||
Shadow::square().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(-8.), px(0.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Square Right",
|
||||
Shadow::square().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(8.), px(0.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Square Top",
|
||||
Shadow::square().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(0.), px(-8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Square Bottom",
|
||||
Shadow::square().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
]),
|
||||
// Rounded large directional shadows
|
||||
div()
|
||||
.border_b_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
|
||||
.flex()
|
||||
.children(vec![
|
||||
example(
|
||||
"Rounded Large Left",
|
||||
Shadow::rounded_large().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(-8.), px(0.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Rounded Large Right",
|
||||
Shadow::rounded_large().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(8.), px(0.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Rounded Large Top",
|
||||
Shadow::rounded_large().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(0.), px(-8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
example(
|
||||
"Rounded Large Bottom",
|
||||
Shadow::rounded_large().shadow(smallvec![BoxShadow {
|
||||
color: hsla(0.0, 0.5, 0.5, 0.3),
|
||||
offset: point(px(0.), px(8.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(0.),
|
||||
}]),
|
||||
),
|
||||
]),
|
||||
// Multiple shadows for different shapes
|
||||
div()
|
||||
.border_b_1()
|
||||
.border_color(hsla(0.0, 0.0, 0.0, 1.0))
|
||||
.flex()
|
||||
.children(vec![
|
||||
example(
|
||||
"Circle Multiple",
|
||||
Shadow::base().shadow(smallvec![
|
||||
BoxShadow {
|
||||
color: hsla(0.0 / 360., 1.0, 0.5, 0.3), // Red
|
||||
offset: point(px(0.), px(-12.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(2.),
|
||||
},
|
||||
BoxShadow {
|
||||
color: hsla(60.0 / 360., 1.0, 0.5, 0.3), // Yellow
|
||||
offset: point(px(12.), px(0.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(2.),
|
||||
},
|
||||
BoxShadow {
|
||||
color: hsla(120.0 / 360., 1.0, 0.5, 0.3), // Green
|
||||
offset: point(px(0.), px(12.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(2.),
|
||||
},
|
||||
BoxShadow {
|
||||
color: hsla(240.0 / 360., 1.0, 0.5, 0.3), // Blue
|
||||
offset: point(px(-12.), px(0.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(2.),
|
||||
},
|
||||
]),
|
||||
),
|
||||
example(
|
||||
"Square Multiple",
|
||||
Shadow::square().shadow(smallvec![
|
||||
BoxShadow {
|
||||
color: hsla(0.0 / 360., 1.0, 0.5, 0.3), // Red
|
||||
offset: point(px(0.), px(-12.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(2.),
|
||||
},
|
||||
BoxShadow {
|
||||
color: hsla(60.0 / 360., 1.0, 0.5, 0.3), // Yellow
|
||||
offset: point(px(12.), px(0.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(2.),
|
||||
},
|
||||
BoxShadow {
|
||||
color: hsla(120.0 / 360., 1.0, 0.5, 0.3), // Green
|
||||
offset: point(px(0.), px(12.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(2.),
|
||||
},
|
||||
BoxShadow {
|
||||
color: hsla(240.0 / 360., 1.0, 0.5, 0.3), // Blue
|
||||
offset: point(px(-12.), px(0.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(2.),
|
||||
},
|
||||
]),
|
||||
),
|
||||
example(
|
||||
"Rounded Large Multiple",
|
||||
Shadow::rounded_large().shadow(smallvec![
|
||||
BoxShadow {
|
||||
color: hsla(0.0 / 360., 1.0, 0.5, 0.3), // Red
|
||||
offset: point(px(0.), px(-12.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(2.),
|
||||
},
|
||||
BoxShadow {
|
||||
color: hsla(60.0 / 360., 1.0, 0.5, 0.3), // Yellow
|
||||
offset: point(px(12.), px(0.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(2.),
|
||||
},
|
||||
BoxShadow {
|
||||
color: hsla(120.0 / 360., 1.0, 0.5, 0.3), // Green
|
||||
offset: point(px(0.), px(12.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(2.),
|
||||
},
|
||||
BoxShadow {
|
||||
color: hsla(240.0 / 360., 1.0, 0.5, 0.3), // Blue
|
||||
offset: point(px(-12.), px(0.)),
|
||||
blur_radius: px(8.),
|
||||
spread_radius: px(2.),
|
||||
},
|
||||
]),
|
||||
),
|
||||
]),
|
||||
]))
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
App::new().run(|cx: &mut AppContext| {
|
||||
let bounds = Bounds::centered(None, size(px(300.0), px(300.0)), cx);
|
||||
let bounds = Bounds::centered(None, size(px(1000.0), px(800.0)), cx);
|
||||
cx.open_window(
|
||||
WindowOptions {
|
||||
window_bounds: Some(WindowBounds::Windowed(bounds)),
|
||||
@@ -28,5 +577,7 @@ fn main() {
|
||||
|cx| cx.new_view(|_cx| Shadow {}),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
cx.activate(true);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1490,7 +1490,7 @@ impl Context for AppContext {
|
||||
|
||||
fn update_window<T, F>(&mut self, handle: AnyWindowHandle, update: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
|
||||
F: FnOnce(AnyView, &mut WindowContext) -> T,
|
||||
{
|
||||
self.update(|cx| {
|
||||
let mut window = cx
|
||||
|
||||
@@ -84,7 +84,7 @@ impl Context for AsyncAppContext {
|
||||
|
||||
fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
|
||||
F: FnOnce(AnyView, &mut WindowContext) -> T,
|
||||
{
|
||||
let app = self.app.upgrade().context("app was released")?;
|
||||
let mut lock = app.borrow_mut();
|
||||
@@ -349,7 +349,7 @@ impl Context for AsyncWindowContext {
|
||||
|
||||
fn update_window<T, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
|
||||
F: FnOnce(AnyView, &mut WindowContext) -> T,
|
||||
{
|
||||
self.app.update_window(window, update)
|
||||
}
|
||||
@@ -369,7 +369,7 @@ impl Context for AsyncWindowContext {
|
||||
impl VisualContext for AsyncWindowContext {
|
||||
fn new_view<V>(
|
||||
&mut self,
|
||||
build_view_state: impl FnOnce(&mut ViewContext<'_, V>) -> V,
|
||||
build_view_state: impl FnOnce(&mut ViewContext<V>) -> V,
|
||||
) -> Self::Result<View<V>>
|
||||
where
|
||||
V: 'static + Render,
|
||||
@@ -381,7 +381,7 @@ impl VisualContext for AsyncWindowContext {
|
||||
fn update_view<V: 'static, R>(
|
||||
&mut self,
|
||||
view: &View<V>,
|
||||
update: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
|
||||
update: impl FnOnce(&mut V, &mut ViewContext<V>) -> R,
|
||||
) -> Self::Result<R> {
|
||||
self.window
|
||||
.update(self, |_, cx| cx.update_view(view, update))
|
||||
@@ -389,7 +389,7 @@ impl VisualContext for AsyncWindowContext {
|
||||
|
||||
fn replace_root_view<V>(
|
||||
&mut self,
|
||||
build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
|
||||
build_view: impl FnOnce(&mut ViewContext<V>) -> V,
|
||||
) -> Self::Result<View<V>>
|
||||
where
|
||||
V: 'static + Render,
|
||||
|
||||
@@ -263,7 +263,7 @@ impl<'a, T> Context for ModelContext<'a, T> {
|
||||
|
||||
fn update_window<R, F>(&mut self, window: AnyWindowHandle, update: F) -> Result<R>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> R,
|
||||
F: FnOnce(AnyView, &mut WindowContext) -> R,
|
||||
{
|
||||
self.app.update_window(window, update)
|
||||
}
|
||||
|
||||
@@ -77,7 +77,7 @@ impl Context for TestAppContext {
|
||||
|
||||
fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
|
||||
F: FnOnce(AnyView, &mut WindowContext) -> T,
|
||||
{
|
||||
let mut lock = self.app.borrow_mut();
|
||||
lock.update_window(window, f)
|
||||
@@ -916,7 +916,7 @@ impl Context for VisualTestContext {
|
||||
|
||||
fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> T,
|
||||
F: FnOnce(AnyView, &mut WindowContext) -> T,
|
||||
{
|
||||
self.cx.update_window(window, f)
|
||||
}
|
||||
@@ -936,7 +936,7 @@ impl Context for VisualTestContext {
|
||||
impl VisualContext for VisualTestContext {
|
||||
fn new_view<V>(
|
||||
&mut self,
|
||||
build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
|
||||
build_view: impl FnOnce(&mut ViewContext<V>) -> V,
|
||||
) -> Self::Result<View<V>>
|
||||
where
|
||||
V: 'static + Render,
|
||||
@@ -949,7 +949,7 @@ impl VisualContext for VisualTestContext {
|
||||
fn update_view<V: 'static, R>(
|
||||
&mut self,
|
||||
view: &View<V>,
|
||||
update: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
|
||||
update: impl FnOnce(&mut V, &mut ViewContext<V>) -> R,
|
||||
) -> Self::Result<R> {
|
||||
self.window
|
||||
.update(&mut self.cx, |_, cx| cx.update_view(view, update))
|
||||
@@ -958,7 +958,7 @@ impl VisualContext for VisualTestContext {
|
||||
|
||||
fn replace_root_view<V>(
|
||||
&mut self,
|
||||
build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
|
||||
build_view: impl FnOnce(&mut ViewContext<V>) -> V,
|
||||
) -> Self::Result<View<V>>
|
||||
where
|
||||
V: 'static + Render,
|
||||
@@ -993,7 +993,7 @@ impl AnyWindowHandle {
|
||||
pub fn build_view<V: Render + 'static>(
|
||||
&self,
|
||||
cx: &mut TestAppContext,
|
||||
build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
|
||||
build_view: impl FnOnce(&mut ViewContext<V>) -> V,
|
||||
) -> View<V> {
|
||||
self.update(cx, |_, cx| cx.new_view(build_view)).unwrap()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use crate::{AnyElement, Element, ElementId, GlobalElementId, IntoElement};
|
||||
use crate::{AnyElement, Element, ElementId, GlobalElementId, IntoElement, WindowContext};
|
||||
|
||||
pub use easing::*;
|
||||
|
||||
@@ -104,7 +104,7 @@ impl<E: IntoElement + 'static> Element for AnimationElement<E> {
|
||||
fn request_layout(
|
||||
&mut self,
|
||||
global_id: Option<&GlobalElementId>,
|
||||
cx: &mut crate::WindowContext,
|
||||
cx: &mut WindowContext,
|
||||
) -> (crate::LayoutId, Self::RequestLayoutState) {
|
||||
cx.with_element_state(global_id.unwrap(), |state, cx| {
|
||||
let state = state.unwrap_or_else(|| AnimationState {
|
||||
@@ -145,7 +145,7 @@ impl<E: IntoElement + 'static> Element for AnimationElement<E> {
|
||||
_id: Option<&GlobalElementId>,
|
||||
_bounds: crate::Bounds<crate::Pixels>,
|
||||
element: &mut Self::RequestLayoutState,
|
||||
cx: &mut crate::WindowContext,
|
||||
cx: &mut WindowContext,
|
||||
) -> Self::PrepaintState {
|
||||
element.prepaint(cx);
|
||||
}
|
||||
@@ -156,7 +156,7 @@ impl<E: IntoElement + 'static> Element for AnimationElement<E> {
|
||||
_bounds: crate::Bounds<crate::Pixels>,
|
||||
element: &mut Self::RequestLayoutState,
|
||||
_: &mut Self::PrepaintState,
|
||||
cx: &mut crate::WindowContext,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
element.paint(cx);
|
||||
}
|
||||
|
||||
@@ -1417,6 +1417,19 @@ impl Interactivity {
|
||||
None
|
||||
};
|
||||
|
||||
let invalidate_tooltip = hitbox
|
||||
.as_ref()
|
||||
.map_or(true, |hitbox| !hitbox.bounds.contains(&cx.mouse_position()));
|
||||
if invalidate_tooltip {
|
||||
if let Some(active_tooltip) = element_state
|
||||
.as_ref()
|
||||
.and_then(|state| state.active_tooltip.as_ref())
|
||||
{
|
||||
*active_tooltip.borrow_mut() = None;
|
||||
self.tooltip_id = None;
|
||||
}
|
||||
}
|
||||
|
||||
let scroll_offset = self.clamp_scroll_position(bounds, &style, cx);
|
||||
let result = f(&style, scroll_offset, hitbox, cx);
|
||||
(result, element_state)
|
||||
@@ -2499,7 +2512,7 @@ impl ScrollAnchor {
|
||||
}
|
||||
}
|
||||
/// Request scroll to this item on the next frame.
|
||||
pub fn scroll_to(&self, cx: &mut WindowContext<'_>) {
|
||||
pub fn scroll_to(&self, cx: &mut WindowContext) {
|
||||
let this = self.clone();
|
||||
|
||||
cx.on_next_frame(move |_| {
|
||||
|
||||
@@ -716,7 +716,7 @@ impl Element for List {
|
||||
fn request_layout(
|
||||
&mut self,
|
||||
_id: Option<&GlobalElementId>,
|
||||
cx: &mut crate::WindowContext,
|
||||
cx: &mut WindowContext,
|
||||
) -> (crate::LayoutId, Self::RequestLayoutState) {
|
||||
let layout_id = match self.sizing_behavior {
|
||||
ListSizingBehavior::Infer => {
|
||||
@@ -827,7 +827,7 @@ impl Element for List {
|
||||
bounds: Bounds<crate::Pixels>,
|
||||
_: &mut Self::RequestLayoutState,
|
||||
prepaint: &mut Self::PrepaintState,
|
||||
cx: &mut crate::WindowContext,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
|
||||
for item in &mut prepaint.layout.item_layouts {
|
||||
|
||||
@@ -472,9 +472,9 @@ pub struct InteractiveText {
|
||||
element_id: ElementId,
|
||||
text: StyledText,
|
||||
click_listener:
|
||||
Option<Box<dyn Fn(&[Range<usize>], InteractiveTextClickEvent, &mut WindowContext<'_>)>>,
|
||||
hover_listener: Option<Box<dyn Fn(Option<usize>, MouseMoveEvent, &mut WindowContext<'_>)>>,
|
||||
tooltip_builder: Option<Rc<dyn Fn(usize, &mut WindowContext<'_>) -> Option<AnyView>>>,
|
||||
Option<Box<dyn Fn(&[Range<usize>], InteractiveTextClickEvent, &mut WindowContext)>>,
|
||||
hover_listener: Option<Box<dyn Fn(Option<usize>, MouseMoveEvent, &mut WindowContext)>>,
|
||||
tooltip_builder: Option<Rc<dyn Fn(usize, &mut WindowContext) -> Option<AnyView>>>,
|
||||
clickable_ranges: Vec<Range<usize>>,
|
||||
}
|
||||
|
||||
@@ -510,7 +510,7 @@ impl InteractiveText {
|
||||
pub fn on_click(
|
||||
mut self,
|
||||
ranges: Vec<Range<usize>>,
|
||||
listener: impl Fn(usize, &mut WindowContext<'_>) + 'static,
|
||||
listener: impl Fn(usize, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.click_listener = Some(Box::new(move |ranges, event, cx| {
|
||||
for (range_ix, range) in ranges.iter().enumerate() {
|
||||
@@ -528,7 +528,7 @@ impl InteractiveText {
|
||||
/// index of the hovered character, or None if the mouse leaves the text.
|
||||
pub fn on_hover(
|
||||
mut self,
|
||||
listener: impl Fn(Option<usize>, MouseMoveEvent, &mut WindowContext<'_>) + 'static,
|
||||
listener: impl Fn(Option<usize>, MouseMoveEvent, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.hover_listener = Some(Box::new(listener));
|
||||
self
|
||||
@@ -537,7 +537,7 @@ impl InteractiveText {
|
||||
/// tooltip lets you specify a tooltip for a given character index in the string.
|
||||
pub fn tooltip(
|
||||
mut self,
|
||||
builder: impl Fn(usize, &mut WindowContext<'_>) -> Option<AnyView> + 'static,
|
||||
builder: impl Fn(usize, &mut WindowContext) -> Option<AnyView> + 'static,
|
||||
) -> Self {
|
||||
self.tooltip_builder = Some(Rc::new(builder));
|
||||
self
|
||||
|
||||
@@ -202,7 +202,7 @@ pub trait Context {
|
||||
/// Update a window for the given handle.
|
||||
fn update_window<T, F>(&mut self, window: AnyWindowHandle, f: F) -> Result<T>
|
||||
where
|
||||
F: FnOnce(AnyView, &mut WindowContext<'_>) -> T;
|
||||
F: FnOnce(AnyView, &mut WindowContext) -> T;
|
||||
|
||||
/// Read a window off of the application context.
|
||||
fn read_window<T, R>(
|
||||
@@ -231,7 +231,7 @@ pub trait VisualContext: Context {
|
||||
/// Construct a new view in the window referenced by this context.
|
||||
fn new_view<V>(
|
||||
&mut self,
|
||||
build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
|
||||
build_view: impl FnOnce(&mut ViewContext<V>) -> V,
|
||||
) -> Self::Result<View<V>>
|
||||
where
|
||||
V: 'static + Render;
|
||||
@@ -240,13 +240,13 @@ pub trait VisualContext: Context {
|
||||
fn update_view<V: 'static, R>(
|
||||
&mut self,
|
||||
view: &View<V>,
|
||||
update: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
|
||||
update: impl FnOnce(&mut V, &mut ViewContext<V>) -> R,
|
||||
) -> Self::Result<R>;
|
||||
|
||||
/// Replace the root view of a window with a new view.
|
||||
fn replace_root_view<V>(
|
||||
&mut self,
|
||||
build_view: impl FnOnce(&mut ViewContext<'_, V>) -> V,
|
||||
build_view: impl FnOnce(&mut ViewContext<V>) -> V,
|
||||
) -> Self::Result<View<V>>
|
||||
where
|
||||
V: 'static + Render;
|
||||
|
||||
@@ -468,7 +468,7 @@ mod test {
|
||||
|
||||
use crate::{
|
||||
self as gpui, div, FocusHandle, InteractiveElement, IntoElement, KeyBinding, Keystroke,
|
||||
ParentElement, Render, TestAppContext, VisualContext,
|
||||
ParentElement, Render, TestAppContext, ViewContext, VisualContext,
|
||||
};
|
||||
|
||||
struct TestView {
|
||||
@@ -480,7 +480,7 @@ mod test {
|
||||
actions!(test, [TestAction]);
|
||||
|
||||
impl Render for TestView {
|
||||
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
div().id("testview").child(
|
||||
div()
|
||||
.key_context("parent")
|
||||
|
||||
@@ -214,6 +214,7 @@ impl BladeAtlasState {
|
||||
},
|
||||
array_layer_count: 1,
|
||||
mip_level_count: 1,
|
||||
sample_count: 1,
|
||||
dimension: gpu::TextureDimension::D2,
|
||||
usage,
|
||||
});
|
||||
|
||||
@@ -174,8 +174,9 @@ impl BladePipelines {
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
fragment: shader.at("fs_quad"),
|
||||
fragment: Some(shader.at("fs_quad")),
|
||||
color_targets,
|
||||
multisample_state: gpu::MultisampleState::default(),
|
||||
}),
|
||||
shadows: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
|
||||
name: "shadows",
|
||||
@@ -187,8 +188,9 @@ impl BladePipelines {
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
fragment: shader.at("fs_shadow"),
|
||||
fragment: Some(shader.at("fs_shadow")),
|
||||
color_targets,
|
||||
multisample_state: gpu::MultisampleState::default(),
|
||||
}),
|
||||
path_rasterization: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
|
||||
name: "path_rasterization",
|
||||
@@ -200,12 +202,13 @@ impl BladePipelines {
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
fragment: shader.at("fs_path_rasterization"),
|
||||
fragment: Some(shader.at("fs_path_rasterization")),
|
||||
color_targets: &[gpu::ColorTargetState {
|
||||
format: PATH_TEXTURE_FORMAT,
|
||||
blend: Some(gpu::BlendState::ADDITIVE),
|
||||
write_mask: gpu::ColorWrites::default(),
|
||||
}],
|
||||
multisample_state: gpu::MultisampleState::default(),
|
||||
}),
|
||||
paths: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
|
||||
name: "paths",
|
||||
@@ -217,8 +220,9 @@ impl BladePipelines {
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
fragment: shader.at("fs_path"),
|
||||
fragment: Some(shader.at("fs_path")),
|
||||
color_targets,
|
||||
multisample_state: gpu::MultisampleState::default(),
|
||||
}),
|
||||
underlines: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
|
||||
name: "underlines",
|
||||
@@ -230,8 +234,9 @@ impl BladePipelines {
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
fragment: shader.at("fs_underline"),
|
||||
fragment: Some(shader.at("fs_underline")),
|
||||
color_targets,
|
||||
multisample_state: gpu::MultisampleState::default(),
|
||||
}),
|
||||
mono_sprites: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
|
||||
name: "mono-sprites",
|
||||
@@ -243,8 +248,9 @@ impl BladePipelines {
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
fragment: shader.at("fs_mono_sprite"),
|
||||
fragment: Some(shader.at("fs_mono_sprite")),
|
||||
color_targets,
|
||||
multisample_state: gpu::MultisampleState::default(),
|
||||
}),
|
||||
poly_sprites: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
|
||||
name: "poly-sprites",
|
||||
@@ -256,8 +262,9 @@ impl BladePipelines {
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
fragment: shader.at("fs_poly_sprite"),
|
||||
fragment: Some(shader.at("fs_poly_sprite")),
|
||||
color_targets,
|
||||
multisample_state: gpu::MultisampleState::default(),
|
||||
}),
|
||||
surfaces: gpu.create_render_pipeline(gpu::RenderPipelineDesc {
|
||||
name: "surfaces",
|
||||
@@ -269,8 +276,9 @@ impl BladePipelines {
|
||||
..Default::default()
|
||||
},
|
||||
depth_stencil: None,
|
||||
fragment: shader.at("fs_surface"),
|
||||
fragment: Some(shader.at("fs_surface")),
|
||||
color_targets,
|
||||
multisample_state: gpu::MultisampleState::default(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
@@ -350,8 +358,10 @@ impl BladeRenderer {
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let core_video_texture_cache = unsafe {
|
||||
use foreign_types::ForeignType as _;
|
||||
CVMetalTextureCache::new(context.gpu.metal_device().as_ptr()).unwrap()
|
||||
CVMetalTextureCache::new(
|
||||
objc2::rc::Retained::as_ptr(&context.gpu.metal_device()) as *mut _
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
@@ -440,13 +450,12 @@ impl BladeRenderer {
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn layer(&self) -> metal::MetalLayer {
|
||||
self.surface.metal_layer()
|
||||
unsafe { foreign_types::ForeignType::from_ptr(self.layer_ptr()) }
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn layer_ptr(&self) -> *mut metal::CAMetalLayer {
|
||||
use metal::foreign_types::ForeignType as _;
|
||||
self.surface.metal_layer().as_ptr()
|
||||
objc2::rc::Retained::as_ptr(&self.surface.metal_layer()) as *mut _
|
||||
}
|
||||
|
||||
#[profiling::function]
|
||||
@@ -678,45 +687,59 @@ impl BladeRenderer {
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
let (t_y, t_cb_cr) = {
|
||||
let (t_y, t_cb_cr) = unsafe {
|
||||
use core_foundation::base::TCFType as _;
|
||||
use std::ptr;
|
||||
|
||||
assert_eq!(
|
||||
surface.image_buffer.pixel_format_type(),
|
||||
media::core_video::kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
|
||||
);
|
||||
surface.image_buffer.pixel_format_type(),
|
||||
media::core_video::kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
|
||||
);
|
||||
|
||||
let y_texture = unsafe {
|
||||
self.core_video_texture_cache
|
||||
.create_texture_from_image(
|
||||
surface.image_buffer.as_concrete_TypeRef(),
|
||||
ptr::null(),
|
||||
metal::MTLPixelFormat::R8Unorm,
|
||||
surface.image_buffer.plane_width(0),
|
||||
surface.image_buffer.plane_height(0),
|
||||
0,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
let cb_cr_texture = unsafe {
|
||||
self.core_video_texture_cache
|
||||
.create_texture_from_image(
|
||||
surface.image_buffer.as_concrete_TypeRef(),
|
||||
ptr::null(),
|
||||
metal::MTLPixelFormat::RG8Unorm,
|
||||
surface.image_buffer.plane_width(1),
|
||||
surface.image_buffer.plane_height(1),
|
||||
1,
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
let y_texture = self
|
||||
.core_video_texture_cache
|
||||
.create_texture_from_image(
|
||||
surface.image_buffer.as_concrete_TypeRef(),
|
||||
ptr::null(),
|
||||
metal::MTLPixelFormat::R8Unorm,
|
||||
surface.image_buffer.plane_width(0),
|
||||
surface.image_buffer.plane_height(0),
|
||||
0,
|
||||
)
|
||||
.unwrap();
|
||||
let cb_cr_texture = self
|
||||
.core_video_texture_cache
|
||||
.create_texture_from_image(
|
||||
surface.image_buffer.as_concrete_TypeRef(),
|
||||
ptr::null(),
|
||||
metal::MTLPixelFormat::RG8Unorm,
|
||||
surface.image_buffer.plane_width(1),
|
||||
surface.image_buffer.plane_height(1),
|
||||
1,
|
||||
)
|
||||
.unwrap();
|
||||
(
|
||||
gpu::TextureView::from_metal_texture(
|
||||
y_texture.as_texture_ref(),
|
||||
&objc2::rc::Retained::retain(
|
||||
foreign_types::ForeignTypeRef::as_ptr(
|
||||
y_texture.as_texture_ref(),
|
||||
)
|
||||
as *mut objc2::runtime::ProtocolObject<
|
||||
dyn objc2_metal::MTLTexture,
|
||||
>,
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
gpu::TextureView::from_metal_texture(
|
||||
cb_cr_texture.as_texture_ref(),
|
||||
&objc2::rc::Retained::retain(
|
||||
foreign_types::ForeignTypeRef::as_ptr(
|
||||
cb_cr_texture.as_texture_ref(),
|
||||
)
|
||||
as *mut objc2::runtime::ProtocolObject<
|
||||
dyn objc2_metal::MTLTexture,
|
||||
>,
|
||||
)
|
||||
.unwrap(),
|
||||
),
|
||||
)
|
||||
};
|
||||
|
||||
@@ -146,19 +146,18 @@ fn handle_size_msg(
|
||||
// Don't resize the renderer when the window is minimized, but record that it was minimized so
|
||||
// that on restore the swap chain can be recreated via `update_drawable_size_even_if_unchanged`.
|
||||
if wparam.0 == SIZE_MINIMIZED as usize {
|
||||
lock.is_minimized = Some(true);
|
||||
lock.restore_from_minimized = lock.callbacks.request_frame.take();
|
||||
return Some(0);
|
||||
}
|
||||
let may_have_been_minimized = lock.is_minimized.unwrap_or(true);
|
||||
lock.is_minimized = Some(false);
|
||||
|
||||
let width = lparam.loword().max(1) as i32;
|
||||
let height = lparam.hiword().max(1) as i32;
|
||||
let new_size = size(DevicePixels(width), DevicePixels(height));
|
||||
let scale_factor = lock.scale_factor;
|
||||
if may_have_been_minimized {
|
||||
if lock.restore_from_minimized.is_some() {
|
||||
lock.renderer
|
||||
.update_drawable_size_even_if_unchanged(new_size);
|
||||
lock.callbacks.request_frame = lock.restore_from_minimized.take();
|
||||
} else {
|
||||
lock.renderer.update_drawable_size(new_size);
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ pub struct WindowsWindowState {
|
||||
pub fullscreen_restore_bounds: Bounds<Pixels>,
|
||||
pub border_offset: WindowBorderOffset,
|
||||
pub scale_factor: f32,
|
||||
pub is_minimized: Option<bool>,
|
||||
pub restore_from_minimized: Option<Box<dyn FnMut(RequestFrameOptions)>>,
|
||||
|
||||
pub callbacks: Callbacks,
|
||||
pub input_handler: Option<PlatformInputHandler>,
|
||||
@@ -94,7 +94,7 @@ impl WindowsWindowState {
|
||||
size: logical_size,
|
||||
};
|
||||
let border_offset = WindowBorderOffset::default();
|
||||
let is_minimized = None;
|
||||
let restore_from_minimized = None;
|
||||
let renderer = windows_renderer::init(gpu_context, hwnd, transparent)?;
|
||||
let callbacks = Callbacks::default();
|
||||
let input_handler = None;
|
||||
@@ -112,7 +112,7 @@ impl WindowsWindowState {
|
||||
fullscreen_restore_bounds,
|
||||
border_offset,
|
||||
scale_factor,
|
||||
is_minimized,
|
||||
restore_from_minimized,
|
||||
callbacks,
|
||||
input_handler,
|
||||
system_key_handled,
|
||||
|
||||
@@ -385,28 +385,20 @@ impl LineLayoutCache {
|
||||
let mut previous_frame = &mut *self.previous_frame.lock();
|
||||
let mut current_frame = &mut *self.current_frame.write();
|
||||
|
||||
if let Some(cached_keys) = previous_frame
|
||||
.used_lines
|
||||
.get(range.start.lines_index..range.end.lines_index)
|
||||
{
|
||||
for key in cached_keys {
|
||||
if let Some((key, line)) = previous_frame.lines.remove_entry(key) {
|
||||
current_frame.lines.insert(key, line);
|
||||
}
|
||||
current_frame.used_lines.push(key.clone());
|
||||
for key in &previous_frame.used_lines[range.start.lines_index..range.end.lines_index] {
|
||||
if let Some((key, line)) = previous_frame.lines.remove_entry(key) {
|
||||
current_frame.lines.insert(key, line);
|
||||
}
|
||||
current_frame.used_lines.push(key.clone());
|
||||
}
|
||||
|
||||
if let Some(cached_keys) = previous_frame
|
||||
.used_wrapped_lines
|
||||
.get(range.start.wrapped_lines_index..range.end.wrapped_lines_index)
|
||||
for key in &previous_frame.used_wrapped_lines
|
||||
[range.start.wrapped_lines_index..range.end.wrapped_lines_index]
|
||||
{
|
||||
for key in cached_keys {
|
||||
if let Some((key, line)) = previous_frame.wrapped_lines.remove_entry(key) {
|
||||
current_frame.wrapped_lines.insert(key, line);
|
||||
}
|
||||
current_frame.used_wrapped_lines.push(key.clone());
|
||||
if let Some((key, line)) = previous_frame.wrapped_lines.remove_entry(key) {
|
||||
current_frame.wrapped_lines.insert(key, line);
|
||||
}
|
||||
current_frame.used_wrapped_lines.push(key.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -69,7 +69,7 @@ impl<V: 'static> View<V> {
|
||||
pub fn update<C, R>(
|
||||
&self,
|
||||
cx: &mut C,
|
||||
f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
|
||||
f: impl FnOnce(&mut V, &mut ViewContext<V>) -> R,
|
||||
) -> C::Result<R>
|
||||
where
|
||||
C: VisualContext,
|
||||
@@ -183,7 +183,7 @@ impl<V: 'static> WeakView<V> {
|
||||
pub fn update<C, R>(
|
||||
&self,
|
||||
cx: &mut C,
|
||||
f: impl FnOnce(&mut V, &mut ViewContext<'_, V>) -> R,
|
||||
f: impl FnOnce(&mut V, &mut ViewContext<V>) -> R,
|
||||
) -> Result<R>
|
||||
where
|
||||
C: VisualContext,
|
||||
|
||||
@@ -1753,17 +1753,12 @@ impl<'a> WindowContext<'a> {
|
||||
.iter_mut()
|
||||
.map(|listener| listener.take()),
|
||||
);
|
||||
if let Some(element_states) = window
|
||||
.rendered_frame
|
||||
.accessed_element_states
|
||||
.get(range.start.accessed_element_states_index..range.end.accessed_element_states_index)
|
||||
{
|
||||
window.next_frame.accessed_element_states.extend(
|
||||
element_states
|
||||
.iter()
|
||||
.map(|(id, type_id)| (GlobalElementId(id.0.clone()), *type_id)),
|
||||
);
|
||||
}
|
||||
window.next_frame.accessed_element_states.extend(
|
||||
window.rendered_frame.accessed_element_states[range.start.accessed_element_states_index
|
||||
..range.end.accessed_element_states_index]
|
||||
.iter()
|
||||
.map(|(id, type_id)| (GlobalElementId(id.0.clone()), *type_id)),
|
||||
);
|
||||
|
||||
window
|
||||
.text_system
|
||||
|
||||
@@ -11,7 +11,7 @@ pub fn derive_render(input: TokenStream) -> TokenStream {
|
||||
impl #impl_generics gpui::Render for #type_name #type_generics
|
||||
#where_clause
|
||||
{
|
||||
fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> impl gpui::Element {
|
||||
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl gpui::Element {
|
||||
gpui::Empty
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,11 @@ use crate::{
|
||||
LanguageModelProviderState, LanguageModelRequest,
|
||||
};
|
||||
use futures::{channel::mpsc, future::BoxFuture, stream::BoxStream, FutureExt, StreamExt};
|
||||
use gpui::{AnyView, AppContext, AsyncAppContext, Task};
|
||||
use gpui::{AnyView, AppContext, AsyncAppContext, Model, Task, WindowContext};
|
||||
use http_client::Result;
|
||||
use parking_lot::Mutex;
|
||||
use serde::Serialize;
|
||||
use std::sync::Arc;
|
||||
use ui::WindowContext;
|
||||
|
||||
pub fn language_model_id() -> LanguageModelId {
|
||||
LanguageModelId::from("fake".to_string())
|
||||
@@ -33,7 +32,7 @@ pub struct FakeLanguageModelProvider;
|
||||
impl LanguageModelProviderState for FakeLanguageModelProvider {
|
||||
type ObservableEntity = ();
|
||||
|
||||
fn observable_entity(&self) -> Option<gpui::Model<Self::ObservableEntity>> {
|
||||
fn observable_entity(&self) -> Option<Model<Self::ObservableEntity>> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
@@ -703,15 +703,11 @@ impl LspLogView {
|
||||
});
|
||||
let editor_subscription = cx.subscribe(
|
||||
&editor,
|
||||
|_, _, event: &EditorEvent, cx: &mut ViewContext<'_, LspLogView>| {
|
||||
cx.emit(event.clone())
|
||||
},
|
||||
|_, _, event: &EditorEvent, cx: &mut ViewContext<LspLogView>| cx.emit(event.clone()),
|
||||
);
|
||||
let search_subscription = cx.subscribe(
|
||||
&editor,
|
||||
|_, _, event: &SearchEvent, cx: &mut ViewContext<'_, LspLogView>| {
|
||||
cx.emit(event.clone())
|
||||
},
|
||||
|_, _, event: &SearchEvent, cx: &mut ViewContext<LspLogView>| cx.emit(event.clone()),
|
||||
);
|
||||
(editor, vec![editor_subscription, search_subscription])
|
||||
}
|
||||
@@ -730,15 +726,11 @@ impl LspLogView {
|
||||
});
|
||||
let editor_subscription = cx.subscribe(
|
||||
&editor,
|
||||
|_, _, event: &EditorEvent, cx: &mut ViewContext<'_, LspLogView>| {
|
||||
cx.emit(event.clone())
|
||||
},
|
||||
|_, _, event: &EditorEvent, cx: &mut ViewContext<LspLogView>| cx.emit(event.clone()),
|
||||
);
|
||||
let search_subscription = cx.subscribe(
|
||||
&editor,
|
||||
|_, _, event: &SearchEvent, cx: &mut ViewContext<'_, LspLogView>| {
|
||||
cx.emit(event.clone())
|
||||
},
|
||||
|_, _, event: &SearchEvent, cx: &mut ViewContext<LspLogView>| cx.emit(event.clone()),
|
||||
);
|
||||
(editor, vec![editor_subscription, search_subscription])
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ impl SyntaxTreeView {
|
||||
}
|
||||
|
||||
impl Render for SyntaxTreeView {
|
||||
fn render(&mut self, cx: &mut gpui::ViewContext<'_, Self>) -> impl IntoElement {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
let mut rendered = div().flex_1();
|
||||
|
||||
if let Some(layer) = self
|
||||
@@ -422,7 +422,7 @@ impl SyntaxTreeToolbarItemView {
|
||||
}
|
||||
}
|
||||
|
||||
fn render_menu(&mut self, cx: &mut ViewContext<'_, Self>) -> Option<PopoverMenu<ContextMenu>> {
|
||||
fn render_menu(&mut self, cx: &mut ViewContext<Self>) -> Option<PopoverMenu<ContextMenu>> {
|
||||
let tree_view = self.tree_view.as_ref()?;
|
||||
let tree_view = tree_view.read(cx);
|
||||
|
||||
@@ -492,7 +492,7 @@ fn format_node_range(node: Node) -> String {
|
||||
}
|
||||
|
||||
impl Render for SyntaxTreeToolbarItemView {
|
||||
fn render(&mut self, cx: &mut ViewContext<'_, Self>) -> impl IntoElement {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
self.render_menu(cx)
|
||||
.unwrap_or_else(|| PopoverMenu::new("Empty Syntax Tree"))
|
||||
}
|
||||
|
||||
@@ -194,6 +194,7 @@
|
||||
"throw"
|
||||
"try"
|
||||
"typeof"
|
||||
"using"
|
||||
"var"
|
||||
"void"
|
||||
"while"
|
||||
|
||||
@@ -284,6 +284,7 @@ impl<F: Future> LspRequestFuture<F::Output> for LspRequest<F> {
|
||||
}
|
||||
|
||||
/// Combined capabilities of the server and the adapter.
|
||||
#[derive(Debug)]
|
||||
pub struct AdapterServerCapabilities {
|
||||
// Reported capabilities by the server
|
||||
pub server_capabilities: ServerCapabilities,
|
||||
|
||||
@@ -614,11 +614,11 @@ impl Element for MarkdownElement {
|
||||
};
|
||||
builder.push_div(
|
||||
div()
|
||||
.mb_1()
|
||||
.h_flex()
|
||||
.mb_2()
|
||||
.line_height(rems(1.3))
|
||||
.items_start()
|
||||
.gap_1()
|
||||
.line_height(rems(1.3))
|
||||
.child(bullet),
|
||||
range,
|
||||
markdown_end,
|
||||
|
||||
@@ -3449,6 +3449,24 @@ impl MultiBufferSnapshot {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buffer_ids_in_selected_rows(
|
||||
&self,
|
||||
selection: Selection<Point>,
|
||||
) -> impl Iterator<Item = BufferId> + '_ {
|
||||
let mut cursor = self.excerpts.cursor::<Point>(&());
|
||||
cursor.seek(&Point::new(selection.start.row, 0), Bias::Right, &());
|
||||
cursor.prev(&());
|
||||
|
||||
iter::from_fn(move || {
|
||||
cursor.next(&());
|
||||
if cursor.start().row <= selection.end.row {
|
||||
cursor.item().map(|item| item.buffer_id)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn excerpts(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (ExcerptId, &BufferSnapshot, ExcerptRange<text::Anchor>)> {
|
||||
|
||||
@@ -25,6 +25,7 @@ theme.workspace = true
|
||||
ui.workspace = true
|
||||
util.workspace = true
|
||||
workspace.workspace = true
|
||||
zed_actions.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
editor = { workspace = true, features = ["test-support"] }
|
||||
|
||||
@@ -4,9 +4,7 @@ use std::{
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use editor::{
|
||||
actions::ToggleOutline, scroll::Autoscroll, Anchor, AnchorRangeExt, Editor, EditorMode,
|
||||
};
|
||||
use editor::{scroll::Autoscroll, Anchor, AnchorRangeExt, Editor, EditorMode};
|
||||
use fuzzy::StringMatch;
|
||||
use gpui::{
|
||||
div, rems, AppContext, DismissEvent, EventEmitter, FocusHandle, FocusableView, HighlightStyle,
|
||||
@@ -24,9 +22,22 @@ use workspace::{DismissDecision, ModalView};
|
||||
|
||||
pub fn init(cx: &mut AppContext) {
|
||||
cx.observe_new_views(OutlineView::register).detach();
|
||||
zed_actions::outline::TOGGLE_OUTLINE
|
||||
.set(|view, cx| {
|
||||
let Ok(view) = view.downcast::<Editor>() else {
|
||||
return;
|
||||
};
|
||||
|
||||
toggle(view, &Default::default(), cx);
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
||||
pub fn toggle(editor: View<Editor>, _: &ToggleOutline, cx: &mut WindowContext) {
|
||||
pub fn toggle(
|
||||
editor: View<Editor>,
|
||||
_: &zed_actions::outline::ToggleOutline,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
let outline = editor
|
||||
.read(cx)
|
||||
.buffer()
|
||||
@@ -459,7 +470,7 @@ mod tests {
|
||||
workspace: &View<Workspace>,
|
||||
cx: &mut VisualTestContext,
|
||||
) -> View<Picker<OutlineViewDelegate>> {
|
||||
cx.dispatch_action(ToggleOutline);
|
||||
cx.dispatch_action(zed_actions::outline::ToggleOutline);
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace
|
||||
.active_modal::<OutlineView>(cx)
|
||||
|
||||
@@ -149,7 +149,7 @@ impl SearchState {
|
||||
previous_matches: HashMap<Range<editor::Anchor>, Arc<OnceLock<SearchData>>>,
|
||||
new_matches: Vec<Range<editor::Anchor>>,
|
||||
theme: Arc<SyntaxTheme>,
|
||||
cx: &mut ViewContext<'_, OutlinePanel>,
|
||||
cx: &mut ViewContext<OutlinePanel>,
|
||||
) -> Self {
|
||||
let (highlight_search_match_tx, highlight_search_match_rx) = channel::unbounded();
|
||||
let (notify_tx, notify_rx) = channel::unbounded::<()>();
|
||||
@@ -1661,7 +1661,7 @@ impl OutlinePanel {
|
||||
}
|
||||
}
|
||||
|
||||
fn reveal_entry_for_selection(&mut self, editor: View<Editor>, cx: &mut ViewContext<'_, Self>) {
|
||||
fn reveal_entry_for_selection(&mut self, editor: View<Editor>, cx: &mut ViewContext<Self>) {
|
||||
if !self.active || !OutlinePanelSettings::get_global(cx).auto_reveal_entries {
|
||||
return;
|
||||
}
|
||||
@@ -2656,7 +2656,7 @@ impl OutlinePanel {
|
||||
self.clear_previous(cx);
|
||||
let buffer_search_subscription = cx.subscribe(
|
||||
&new_active_editor,
|
||||
|outline_panel: &mut Self, _, e: &SearchEvent, cx: &mut ViewContext<'_, Self>| {
|
||||
|outline_panel: &mut Self, _, e: &SearchEvent, cx: &mut ViewContext<Self>| {
|
||||
if matches!(e, SearchEvent::MatchesInvalidated) {
|
||||
outline_panel.update_search_matches(cx);
|
||||
};
|
||||
@@ -2675,7 +2675,7 @@ impl OutlinePanel {
|
||||
self.update_fs_entries(new_active_editor, None, cx);
|
||||
}
|
||||
|
||||
fn clear_previous(&mut self, cx: &mut WindowContext<'_>) {
|
||||
fn clear_previous(&mut self, cx: &mut WindowContext) {
|
||||
self.fs_entries_update_task = Task::ready(());
|
||||
self.outline_fetch_tasks.clear();
|
||||
self.cached_entries_update_task = Task::ready(());
|
||||
@@ -3124,7 +3124,7 @@ impl OutlinePanel {
|
||||
&self,
|
||||
is_singleton: bool,
|
||||
query: Option<String>,
|
||||
cx: &mut ViewContext<'_, Self>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Task<(Vec<CachedEntry>, Option<usize>)> {
|
||||
let project = self.project.clone();
|
||||
let Some(active_editor) = self.active_editor() else {
|
||||
@@ -4078,7 +4078,7 @@ impl OutlinePanel {
|
||||
query: Option<String>,
|
||||
show_indent_guides: bool,
|
||||
indent_size: f32,
|
||||
cx: &mut ViewContext<'_, Self>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Div {
|
||||
let contents = if self.cached_entries.is_empty() {
|
||||
let header = if self.updating_fs_entries {
|
||||
@@ -4266,7 +4266,7 @@ impl OutlinePanel {
|
||||
v_flex().w_full().flex_1().overflow_hidden().child(contents)
|
||||
}
|
||||
|
||||
fn render_filter_footer(&mut self, pinned: bool, cx: &mut ViewContext<'_, Self>) -> Div {
|
||||
fn render_filter_footer(&mut self, pinned: bool, cx: &mut ViewContext<Self>) -> Div {
|
||||
v_flex().flex_none().child(horizontal_separator(cx)).child(
|
||||
h_flex()
|
||||
.p_2()
|
||||
@@ -4468,6 +4468,10 @@ impl Panel for OutlinePanel {
|
||||
})
|
||||
.detach()
|
||||
}
|
||||
|
||||
fn activation_priority(&self) -> u32 {
|
||||
5
|
||||
}
|
||||
}
|
||||
|
||||
impl FocusableView for OutlinePanel {
|
||||
|
||||
@@ -16,7 +16,7 @@ pub(crate) enum Head {
|
||||
impl Head {
|
||||
pub fn editor<V: 'static>(
|
||||
placeholder_text: Arc<str>,
|
||||
edit_handler: impl FnMut(&mut V, View<Editor>, &EditorEvent, &mut ViewContext<'_, V>) + 'static,
|
||||
edit_handler: impl FnMut(&mut V, View<Editor>, &EditorEvent, &mut ViewContext<V>) + 'static,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self {
|
||||
let editor = cx.new_view(|cx| {
|
||||
@@ -29,7 +29,7 @@ impl Head {
|
||||
}
|
||||
|
||||
pub fn empty<V: 'static>(
|
||||
blur_handler: impl FnMut(&mut V, &mut ViewContext<'_, V>) + 'static,
|
||||
blur_handler: impl FnMut(&mut V, &mut ViewContext<V>) + 'static,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self {
|
||||
let head = cx.new_view(EmptyHead::new);
|
||||
|
||||
@@ -425,7 +425,7 @@ impl<D: PickerDelegate> Picker<D> {
|
||||
self.cancel(&menu::Cancel, cx);
|
||||
}
|
||||
|
||||
pub fn refresh_placeholder(&mut self, cx: &mut WindowContext<'_>) {
|
||||
pub fn refresh_placeholder(&mut self, cx: &mut WindowContext) {
|
||||
match &self.head {
|
||||
Head::Editor(view) => {
|
||||
let placeholder = self.delegate.placeholder_text(cx);
|
||||
@@ -493,7 +493,7 @@ impl<D: PickerDelegate> Picker<D> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_query(&self, query: impl Into<Arc<str>>, cx: &mut WindowContext<'_>) {
|
||||
pub fn set_query(&self, query: impl Into<Arc<str>>, cx: &mut WindowContext) {
|
||||
if let Head::Editor(ref editor) = &self.head {
|
||||
editor.update(cx, |editor, cx| {
|
||||
editor.set_text(query, cx);
|
||||
|
||||
@@ -1918,6 +1918,7 @@ impl LspCommand for GetCompletions {
|
||||
new_text,
|
||||
server_id,
|
||||
lsp_completion,
|
||||
resolved: false,
|
||||
}
|
||||
})
|
||||
.collect())
|
||||
|
||||
@@ -2353,8 +2353,16 @@ impl LocalLspStore {
|
||||
let (mut edits, mut snippet_edits) = (vec![], vec![]);
|
||||
for edit in op.edits {
|
||||
match edit {
|
||||
Edit::Plain(edit) => edits.push(edit),
|
||||
Edit::Annotated(edit) => edits.push(edit.text_edit),
|
||||
Edit::Plain(edit) => {
|
||||
if !edits.contains(&edit) {
|
||||
edits.push(edit)
|
||||
}
|
||||
}
|
||||
Edit::Annotated(edit) => {
|
||||
if !edits.contains(&edit.text_edit) {
|
||||
edits.push(edit.text_edit)
|
||||
}
|
||||
}
|
||||
Edit::Snippet(edit) => {
|
||||
let Ok(snippet) = Snippet::parse(&edit.snippet.value)
|
||||
else {
|
||||
@@ -2365,10 +2373,13 @@ impl LocalLspStore {
|
||||
snippet_edits.push((edit.range, snippet));
|
||||
} else {
|
||||
// Since this buffer is not focused, apply a normal edit.
|
||||
edits.push(TextEdit {
|
||||
let new_edit = TextEdit {
|
||||
range: edit.range,
|
||||
new_text: snippet.text,
|
||||
});
|
||||
};
|
||||
if !edits.contains(&new_edit) {
|
||||
edits.push(new_edit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4152,38 +4163,27 @@ impl LspStore {
|
||||
let mut did_resolve = false;
|
||||
if let Some((client, project_id)) = client {
|
||||
for completion_index in completion_indices {
|
||||
let (server_id, completion) = {
|
||||
let completions = completions.borrow_mut();
|
||||
let completion = &completions[completion_index];
|
||||
did_resolve = true;
|
||||
let server_id = completion.server_id;
|
||||
let completion = completion.lsp_completion.clone();
|
||||
let server_id = completions.borrow()[completion_index].server_id;
|
||||
|
||||
(server_id, completion)
|
||||
};
|
||||
|
||||
Self::resolve_completion_remote(
|
||||
if Self::resolve_completion_remote(
|
||||
project_id,
|
||||
server_id,
|
||||
buffer_id,
|
||||
completions.clone(),
|
||||
completion_index,
|
||||
completion,
|
||||
client.clone(),
|
||||
language_registry.clone(),
|
||||
)
|
||||
.await;
|
||||
.await
|
||||
.log_err()
|
||||
.is_some()
|
||||
{
|
||||
did_resolve = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for completion_index in completion_indices {
|
||||
let (server_id, completion) = {
|
||||
let completions = completions.borrow_mut();
|
||||
let completion = &completions[completion_index];
|
||||
let server_id = completion.server_id;
|
||||
let completion = completion.lsp_completion.clone();
|
||||
|
||||
(server_id, completion)
|
||||
};
|
||||
let server_id = completions.borrow()[completion_index].server_id;
|
||||
|
||||
let server_and_adapter = this
|
||||
.read_with(&cx, |lsp_store, _| {
|
||||
@@ -4198,17 +4198,27 @@ impl LspStore {
|
||||
continue;
|
||||
};
|
||||
|
||||
did_resolve = true;
|
||||
Self::resolve_completion_local(
|
||||
let resolved = Self::resolve_completion_local(
|
||||
server,
|
||||
adapter,
|
||||
&buffer_snapshot,
|
||||
completions.clone(),
|
||||
completion_index,
|
||||
completion,
|
||||
language_registry.clone(),
|
||||
)
|
||||
.await;
|
||||
.await
|
||||
.log_err()
|
||||
.is_some();
|
||||
if resolved {
|
||||
Self::regenerate_completion_labels(
|
||||
adapter,
|
||||
&buffer_snapshot,
|
||||
completions.clone(),
|
||||
completion_index,
|
||||
language_registry.clone(),
|
||||
)
|
||||
.await
|
||||
.log_err();
|
||||
did_resolve = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4218,13 +4228,10 @@ impl LspStore {
|
||||
|
||||
async fn resolve_completion_local(
|
||||
server: Arc<lsp::LanguageServer>,
|
||||
adapter: Arc<CachedLspAdapter>,
|
||||
snapshot: &BufferSnapshot,
|
||||
completions: Rc<RefCell<Box<[Completion]>>>,
|
||||
completion_index: usize,
|
||||
completion: lsp::CompletionItem,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
) {
|
||||
) -> Result<()> {
|
||||
let can_resolve = server
|
||||
.capabilities()
|
||||
.completion_provider
|
||||
@@ -4232,30 +4239,17 @@ impl LspStore {
|
||||
.and_then(|options| options.resolve_provider)
|
||||
.unwrap_or(false);
|
||||
if !can_resolve {
|
||||
return;
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let request = server.request::<lsp::request::ResolveCompletionItem>(completion);
|
||||
let Some(completion_item) = request.await.log_err() else {
|
||||
return;
|
||||
let request = {
|
||||
let completion = &completions.borrow()[completion_index];
|
||||
if completion.resolved {
|
||||
return Ok(());
|
||||
}
|
||||
server.request::<lsp::request::ResolveCompletionItem>(completion.lsp_completion.clone())
|
||||
};
|
||||
|
||||
if let Some(lsp_documentation) = completion_item.documentation.as_ref() {
|
||||
let documentation = language::prepare_completion_documentation(
|
||||
lsp_documentation,
|
||||
&language_registry,
|
||||
snapshot.language().cloned(),
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut completions = completions.borrow_mut();
|
||||
let completion = &mut completions[completion_index];
|
||||
completion.documentation = Some(documentation);
|
||||
} else {
|
||||
let mut completions = completions.borrow_mut();
|
||||
let completion = &mut completions[completion_index];
|
||||
completion.documentation = Some(Documentation::Undocumented);
|
||||
}
|
||||
let completion_item = request.await?;
|
||||
|
||||
if let Some(text_edit) = completion_item.text_edit.as_ref() {
|
||||
// Technically we don't have to parse the whole `text_edit`, since the only
|
||||
@@ -4283,28 +4277,61 @@ impl LspStore {
|
||||
}
|
||||
}
|
||||
|
||||
let mut completions = completions.borrow_mut();
|
||||
let completion = &mut completions[completion_index];
|
||||
completion.lsp_completion = completion_item;
|
||||
completion.resolved = true;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn regenerate_completion_labels(
|
||||
adapter: Arc<CachedLspAdapter>,
|
||||
snapshot: &BufferSnapshot,
|
||||
completions: Rc<RefCell<Box<[Completion]>>>,
|
||||
completion_index: usize,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
) -> Result<()> {
|
||||
let completion_item = completions.borrow()[completion_index]
|
||||
.lsp_completion
|
||||
.clone();
|
||||
if let Some(lsp_documentation) = completion_item.documentation.as_ref() {
|
||||
let documentation = language::prepare_completion_documentation(
|
||||
lsp_documentation,
|
||||
&language_registry,
|
||||
snapshot.language().cloned(),
|
||||
)
|
||||
.await;
|
||||
|
||||
let mut completions = completions.borrow_mut();
|
||||
let completion = &mut completions[completion_index];
|
||||
completion.documentation = Some(documentation);
|
||||
} else {
|
||||
let mut completions = completions.borrow_mut();
|
||||
let completion = &mut completions[completion_index];
|
||||
completion.documentation = Some(Documentation::Undocumented);
|
||||
}
|
||||
|
||||
// NB: Zed does not have `details` inside the completion resolve capabilities, but certain language servers violate the spec and do not return `details` immediately, e.g. https://github.com/yioneko/vtsls/issues/213
|
||||
// So we have to update the label here anyway...
|
||||
let new_label = match snapshot.language() {
|
||||
Some(language) => adapter
|
||||
.labels_for_completions(&[completion_item.clone()], language)
|
||||
.await
|
||||
.log_err()
|
||||
.unwrap_or_default(),
|
||||
Some(language) => {
|
||||
adapter
|
||||
.labels_for_completions(&[completion_item.clone()], language)
|
||||
.await?
|
||||
}
|
||||
None => Vec::new(),
|
||||
}
|
||||
.pop()
|
||||
.flatten()
|
||||
.unwrap_or_else(|| {
|
||||
CodeLabel::plain(
|
||||
completion_item.label.clone(),
|
||||
completion_item.label,
|
||||
completion_item.filter_text.as_deref(),
|
||||
)
|
||||
});
|
||||
|
||||
let mut completions = completions.borrow_mut();
|
||||
let completion = &mut completions[completion_index];
|
||||
completion.lsp_completion = completion_item;
|
||||
if completion.label.filter_text() == new_label.filter_text() {
|
||||
completion.label = new_label;
|
||||
} else {
|
||||
@@ -4317,6 +4344,8 @@ impl LspStore {
|
||||
new_label.filter_text()
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
@@ -4326,29 +4355,30 @@ impl LspStore {
|
||||
buffer_id: BufferId,
|
||||
completions: Rc<RefCell<Box<[Completion]>>>,
|
||||
completion_index: usize,
|
||||
completion: lsp::CompletionItem,
|
||||
client: AnyProtoClient,
|
||||
language_registry: Arc<LanguageRegistry>,
|
||||
) {
|
||||
) -> Result<()> {
|
||||
let lsp_completion = {
|
||||
let completion = &completions.borrow()[completion_index];
|
||||
if completion.resolved {
|
||||
return Ok(());
|
||||
}
|
||||
serde_json::to_string(&completion.lsp_completion)
|
||||
.unwrap()
|
||||
.into_bytes()
|
||||
};
|
||||
let request = proto::ResolveCompletionDocumentation {
|
||||
project_id,
|
||||
language_server_id: server_id.0 as u64,
|
||||
lsp_completion: serde_json::to_string(&completion).unwrap().into_bytes(),
|
||||
lsp_completion,
|
||||
buffer_id: buffer_id.into(),
|
||||
};
|
||||
|
||||
let Some(response) = client
|
||||
let response = client
|
||||
.request(request)
|
||||
.await
|
||||
.context("completion documentation resolve proto request")
|
||||
.log_err()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
let Some(lsp_completion) = serde_json::from_slice(&response.lsp_completion).log_err()
|
||||
else {
|
||||
return;
|
||||
};
|
||||
.context("completion documentation resolve proto request")?;
|
||||
let lsp_completion = serde_json::from_slice(&response.lsp_completion)?;
|
||||
|
||||
let documentation = if response.documentation.is_empty() {
|
||||
Documentation::Undocumented
|
||||
@@ -4366,6 +4396,7 @@ impl LspStore {
|
||||
let completion = &mut completions[completion_index];
|
||||
completion.documentation = Some(documentation);
|
||||
completion.lsp_completion = lsp_completion;
|
||||
completion.resolved = true;
|
||||
|
||||
let old_range = response
|
||||
.old_start
|
||||
@@ -4377,12 +4408,15 @@ impl LspStore {
|
||||
completion.old_range = old_start..old_end;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn apply_additional_edits_for_completion(
|
||||
&self,
|
||||
buffer_handle: Model<Buffer>,
|
||||
completion: Completion,
|
||||
completions: Rc<RefCell<Box<[Completion]>>>,
|
||||
completion_index: usize,
|
||||
push_to_history: bool,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Option<Transaction>>> {
|
||||
@@ -4391,8 +4425,9 @@ impl LspStore {
|
||||
|
||||
if let Some((client, project_id)) = self.upstream_client() {
|
||||
cx.spawn(move |_, mut cx| async move {
|
||||
let response = client
|
||||
.request(proto::ApplyCompletionAdditionalEdits {
|
||||
let request = {
|
||||
let completion = completions.borrow()[completion_index].clone();
|
||||
proto::ApplyCompletionAdditionalEdits {
|
||||
project_id,
|
||||
buffer_id: buffer_id.into(),
|
||||
completion: Some(Self::serialize_completion(&CoreCompletion {
|
||||
@@ -4400,9 +4435,13 @@ impl LspStore {
|
||||
new_text: completion.new_text,
|
||||
server_id: completion.server_id,
|
||||
lsp_completion: completion.lsp_completion,
|
||||
resolved: completion.resolved,
|
||||
})),
|
||||
})
|
||||
.await?;
|
||||
}
|
||||
};
|
||||
|
||||
let response = client.request(request).await?;
|
||||
completions.borrow_mut()[completion_index].resolved = true;
|
||||
|
||||
if let Some(transaction) = response.transaction {
|
||||
let transaction = language::proto::deserialize_transaction(transaction)?;
|
||||
@@ -4422,34 +4461,31 @@ impl LspStore {
|
||||
}
|
||||
})
|
||||
} else {
|
||||
let server_id = completion.server_id;
|
||||
let lang_server = match self.language_server_for_local_buffer(buffer, server_id, cx) {
|
||||
let server_id = completions.borrow()[completion_index].server_id;
|
||||
let server = match self.language_server_for_local_buffer(buffer, server_id, cx) {
|
||||
Some((_, server)) => server.clone(),
|
||||
_ => return Task::ready(Ok(Default::default())),
|
||||
_ => return Task::ready(Ok(None)),
|
||||
};
|
||||
let snapshot = buffer_handle.read(&cx).snapshot();
|
||||
|
||||
cx.spawn(move |this, mut cx| async move {
|
||||
let can_resolve = lang_server
|
||||
.capabilities()
|
||||
.completion_provider
|
||||
.as_ref()
|
||||
.and_then(|options| options.resolve_provider)
|
||||
.unwrap_or(false);
|
||||
let additional_text_edits = if can_resolve {
|
||||
lang_server
|
||||
.request::<lsp::request::ResolveCompletionItem>(completion.lsp_completion)
|
||||
.await?
|
||||
.additional_text_edits
|
||||
} else {
|
||||
completion.lsp_completion.additional_text_edits
|
||||
};
|
||||
Self::resolve_completion_local(
|
||||
server.clone(),
|
||||
&snapshot,
|
||||
completions.clone(),
|
||||
completion_index,
|
||||
)
|
||||
.await
|
||||
.context("resolving completion")?;
|
||||
let completion = completions.borrow()[completion_index].clone();
|
||||
let additional_text_edits = completion.lsp_completion.additional_text_edits;
|
||||
if let Some(edits) = additional_text_edits {
|
||||
let edits = this
|
||||
.update(&mut cx, |this, cx| {
|
||||
this.as_local_mut().unwrap().edits_from_lsp(
|
||||
&buffer_handle,
|
||||
edits,
|
||||
lang_server.server_id(),
|
||||
server.server_id(),
|
||||
None,
|
||||
cx,
|
||||
)
|
||||
@@ -6803,7 +6839,7 @@ impl LspStore {
|
||||
let apply_additional_edits = this.update(&mut cx, |this, cx| {
|
||||
this.apply_additional_edits_for_completion(
|
||||
buffer,
|
||||
Completion {
|
||||
Rc::new(RefCell::new(Box::new([Completion {
|
||||
old_range: completion.old_range,
|
||||
new_text: completion.new_text,
|
||||
lsp_completion: completion.lsp_completion,
|
||||
@@ -6815,7 +6851,9 @@ impl LspStore {
|
||||
filter_range: Default::default(),
|
||||
},
|
||||
confirm: None,
|
||||
},
|
||||
resolved: completion.resolved,
|
||||
}]))),
|
||||
0,
|
||||
false,
|
||||
cx,
|
||||
)
|
||||
@@ -7780,6 +7818,7 @@ impl LspStore {
|
||||
new_text: completion.new_text.clone(),
|
||||
server_id: completion.server_id.0 as u64,
|
||||
lsp_completion: serde_json::to_vec(&completion.lsp_completion).unwrap(),
|
||||
resolved: completion.resolved,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7799,6 +7838,7 @@ impl LspStore {
|
||||
new_text: completion.new_text,
|
||||
server_id: LanguageServerId(completion.server_id as usize),
|
||||
lsp_completion,
|
||||
resolved: completion.resolved,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7900,6 +7940,7 @@ async fn populate_labels_for_completions(
|
||||
documentation,
|
||||
lsp_completion,
|
||||
confirm: None,
|
||||
resolved: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -73,10 +73,8 @@ use snippet::Snippet;
|
||||
use snippet_provider::SnippetProvider;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
cell::RefCell,
|
||||
ops::Range,
|
||||
path::{Component, Path, PathBuf},
|
||||
rc::Rc,
|
||||
str,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
@@ -353,6 +351,8 @@ pub struct Completion {
|
||||
pub documentation: Option<Documentation>,
|
||||
/// The raw completion provided by the language server.
|
||||
pub lsp_completion: lsp::CompletionItem,
|
||||
/// Whether this completion has been resolved, to ensure it happens once per completion.
|
||||
pub resolved: bool,
|
||||
/// An optional callback to invoke when this completion is confirmed.
|
||||
/// Returns, whether new completions should be retriggered after the current one.
|
||||
/// If `true` is returned, the editor will show a new completion menu after this completion is confirmed.
|
||||
@@ -380,6 +380,7 @@ pub(crate) struct CoreCompletion {
|
||||
new_text: String,
|
||||
server_id: LanguageServerId,
|
||||
lsp_completion: lsp::CompletionItem,
|
||||
resolved: bool,
|
||||
}
|
||||
|
||||
/// A code action provided by a language server.
|
||||
@@ -2863,35 +2864,6 @@ impl Project {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn resolve_completions(
|
||||
&self,
|
||||
buffer: Model<Buffer>,
|
||||
completion_indices: Vec<usize>,
|
||||
completions: Rc<RefCell<Box<[Completion]>>>,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<bool>> {
|
||||
self.lsp_store.update(cx, |lsp_store, cx| {
|
||||
lsp_store.resolve_completions(buffer, completion_indices, completions, cx)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn apply_additional_edits_for_completion(
|
||||
&self,
|
||||
buffer_handle: Model<Buffer>,
|
||||
completion: Completion,
|
||||
push_to_history: bool,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Task<Result<Option<Transaction>>> {
|
||||
self.lsp_store.update(cx, |lsp_store, cx| {
|
||||
lsp_store.apply_additional_edits_for_completion(
|
||||
buffer_handle,
|
||||
completion,
|
||||
push_to_history,
|
||||
cx,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn code_actions<T: Clone + ToOffset>(
|
||||
&mut self,
|
||||
buffer_handle: &Model<Buffer>,
|
||||
|
||||
@@ -1209,7 +1209,7 @@ impl ProjectPanel {
|
||||
self.remove(false, action.skip_prompt, cx);
|
||||
}
|
||||
|
||||
fn remove(&mut self, trash: bool, skip_prompt: bool, cx: &mut ViewContext<'_, ProjectPanel>) {
|
||||
fn remove(&mut self, trash: bool, skip_prompt: bool, cx: &mut ViewContext<ProjectPanel>) {
|
||||
maybe!({
|
||||
let items_to_delete = self.disjoint_entries(cx);
|
||||
if items_to_delete.is_empty() {
|
||||
@@ -3705,7 +3705,7 @@ impl ProjectPanel {
|
||||
project: Model<Project>,
|
||||
entry_id: ProjectEntryId,
|
||||
skip_ignored: bool,
|
||||
cx: &mut ViewContext<'_, Self>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
if let Some(worktree) = project.read(cx).worktree_for_entry(entry_id, cx) {
|
||||
let worktree = worktree.read(cx);
|
||||
@@ -3810,7 +3810,7 @@ fn item_width_estimate(depth: usize, item_text_chars: usize, is_symlink: bool) -
|
||||
}
|
||||
|
||||
impl Render for ProjectPanel {
|
||||
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> impl IntoElement {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
let has_worktree = !self.visible_entries.is_empty();
|
||||
let project = self.project.read(cx);
|
||||
let indent_size = ProjectPanelSettings::get_global(cx).indent_size;
|
||||
@@ -4252,6 +4252,10 @@ impl Panel for ProjectPanel {
|
||||
.map_or(false, |entry| entry.is_dir())
|
||||
})
|
||||
}
|
||||
|
||||
fn activation_priority(&self) -> u32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
impl FocusableView for ProjectPanel {
|
||||
|
||||
@@ -927,6 +927,7 @@ message Completion {
|
||||
string new_text = 3;
|
||||
uint64 server_id = 4;
|
||||
bytes lsp_completion = 5;
|
||||
bool resolved = 6;
|
||||
}
|
||||
|
||||
message GetCodeActions {
|
||||
|
||||
@@ -61,7 +61,7 @@ struct CreateRemoteServer {
|
||||
}
|
||||
|
||||
impl CreateRemoteServer {
|
||||
fn new(cx: &mut WindowContext<'_>) -> Self {
|
||||
fn new(cx: &mut WindowContext) -> Self {
|
||||
let address_editor = cx.new_view(Editor::single_line);
|
||||
address_editor.update(cx, |this, cx| {
|
||||
this.focus_handle(cx).focus(cx);
|
||||
@@ -88,7 +88,7 @@ struct EditNicknameState {
|
||||
}
|
||||
|
||||
impl EditNicknameState {
|
||||
fn new(index: usize, cx: &mut WindowContext<'_>) -> Self {
|
||||
fn new(index: usize, cx: &mut WindowContext) -> Self {
|
||||
let this = Self {
|
||||
index,
|
||||
editor: cx.new_view(Editor::single_line),
|
||||
@@ -264,7 +264,7 @@ struct DefaultState {
|
||||
servers: Vec<ProjectEntry>,
|
||||
}
|
||||
impl DefaultState {
|
||||
fn new(cx: &WindowContext<'_>) -> Self {
|
||||
fn new(cx: &WindowContext) -> Self {
|
||||
let handle = ScrollHandle::new();
|
||||
let scrollbar = ScrollbarState::new(handle.clone());
|
||||
let add_new_server = NavigableEntry::new(&handle, cx);
|
||||
@@ -309,7 +309,7 @@ enum Mode {
|
||||
}
|
||||
|
||||
impl Mode {
|
||||
fn default_mode(cx: &WindowContext<'_>) -> Self {
|
||||
fn default_mode(cx: &WindowContext) -> Self {
|
||||
Self::Default(DefaultState::new(cx))
|
||||
}
|
||||
}
|
||||
@@ -1003,7 +1003,7 @@ impl RemoteServerProjects {
|
||||
fn callback(
|
||||
workspace: WeakView<Workspace>,
|
||||
connection_string: SharedString,
|
||||
cx: &mut WindowContext<'_>,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
cx.write_to_clipboard(ClipboardItem::new_string(
|
||||
connection_string.to_string(),
|
||||
@@ -1069,7 +1069,7 @@ impl RemoteServerProjects {
|
||||
remote_servers: View<RemoteServerProjects>,
|
||||
index: usize,
|
||||
connection_string: SharedString,
|
||||
cx: &mut WindowContext<'_>,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
let prompt_message =
|
||||
format!("Remove server `{}`?", connection_string);
|
||||
|
||||
@@ -357,7 +357,7 @@ impl RenderOnce for SshConnectionHeader {
|
||||
}
|
||||
|
||||
impl Render for SshConnectionModal {
|
||||
fn render(&mut self, cx: &mut ui::ViewContext<Self>) -> impl ui::IntoElement {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl ui::IntoElement {
|
||||
let nickname = self.prompt.read(cx).nickname.clone();
|
||||
let connection_string = self.prompt.read(cx).connection_string.clone();
|
||||
|
||||
|
||||
@@ -10,4 +10,3 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
gpui.workspace = true
|
||||
once_cell.workspace = true
|
||||
|
||||
@@ -2,24 +2,23 @@
|
||||
|
||||
#![deny(missing_docs)]
|
||||
|
||||
use std::{env, str::FromStr};
|
||||
use std::{env, str::FromStr, sync::LazyLock};
|
||||
|
||||
use gpui::{AppContext, Global, SemanticVersion};
|
||||
use once_cell::sync::Lazy;
|
||||
|
||||
/// stable | dev | nightly | preview
|
||||
pub static RELEASE_CHANNEL_NAME: Lazy<String> = if cfg!(debug_assertions) {
|
||||
Lazy::new(|| {
|
||||
pub static RELEASE_CHANNEL_NAME: LazyLock<String> = LazyLock::new(|| {
|
||||
if cfg!(debug_assertions) {
|
||||
env::var("ZED_RELEASE_CHANNEL")
|
||||
.unwrap_or_else(|_| include_str!("../../zed/RELEASE_CHANNEL").trim().to_string())
|
||||
})
|
||||
} else {
|
||||
Lazy::new(|| include_str!("../../zed/RELEASE_CHANNEL").trim().to_string())
|
||||
};
|
||||
} else {
|
||||
include_str!("../../zed/RELEASE_CHANNEL").trim().to_string()
|
||||
}
|
||||
});
|
||||
|
||||
#[doc(hidden)]
|
||||
pub static RELEASE_CHANNEL: Lazy<ReleaseChannel> =
|
||||
Lazy::new(|| match ReleaseChannel::from_str(&RELEASE_CHANNEL_NAME) {
|
||||
pub static RELEASE_CHANNEL: LazyLock<ReleaseChannel> =
|
||||
LazyLock::new(|| match ReleaseChannel::from_str(&RELEASE_CHANNEL_NAME) {
|
||||
Ok(channel) => channel,
|
||||
_ => panic!("invalid release channel {}", *RELEASE_CHANNEL_NAME),
|
||||
});
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user