Compare commits

..

1 Commits

Author SHA1 Message Date
Piotr Osiewicz
4d3890e595 ci: Check notarization timings 2025-02-17 11:55:03 +01:00
250 changed files with 3414 additions and 4330 deletions

View File

@@ -29,5 +29,5 @@ jobs:
- name: Run Issue Response
run: pnpm run --dir script/issue_response start
env:
ISSUE_RESPONSE_GITHUB_TOKEN: ${{ secrets.ISSUE_RESPONSE_GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SLACK_ISSUE_RESPONSE_WEBHOOK_URL: ${{ secrets.SLACK_ISSUE_RESPONSE_WEBHOOK_URL }}

398
Cargo.lock generated
View File

@@ -27,7 +27,7 @@ version = "0.24.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1"
dependencies = [
"gimli",
"gimli 0.31.1",
]
[[package]]
@@ -83,9 +83,8 @@ dependencies = [
[[package]]
name = "alacritty_terminal"
version = "0.25.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5bccc2e60c2112dc8e8a722d6d30f2bb1a6a7b5d0e65fa695e09e57415dca7f7"
version = "0.25.0-dev"
source = "git+https://github.com/alacritty/alacritty.git?rev=5e78d20c709cb1ab8d44ca7a8702cc26d779227c#5e78d20c709cb1ab8d44ca7a8702cc26d779227c"
dependencies = [
"base64 0.22.1",
"bitflags 2.8.0",
@@ -1142,6 +1141,7 @@ dependencies = [
"gpui",
"http_client",
"markdown_preview",
"menu",
"release_channel",
"serde",
"serde_json",
@@ -2057,9 +2057,6 @@ name = "bumpalo"
version = "3.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
dependencies = [
"allocator-api2",
]
[[package]]
name = "by_address"
@@ -2424,7 +2421,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d067ad48b8650848b989a59a86c6c36a995d02d2bf778d45c3c5d57bc2718f02"
dependencies = [
"smallvec",
"target-lexicon 0.12.16",
"target-lexicon",
]
[[package]]
@@ -3331,18 +3328,18 @@ dependencies = [
[[package]]
name = "cranelift-bforest"
version = "0.116.1"
version = "0.112.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e15d04a0ce86cb36ead88ad68cf693ffd6cda47052b9e0ac114bc47fd9cd23c4"
checksum = "69792bd40d21be8059f7c709f44200ded3bbd073df7eb3fa3c282b387c7ffa5b"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-bitset"
version = "0.116.1"
version = "0.112.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c6e3969a7ce267259ce244b7867c5d3bc9e65b0a87e81039588dfdeaede9f34"
checksum = "38da1eb6f7d8cdfa92f05acfae63c9a1d7a337e49ce7a2d0769c7fa03a2613a5"
dependencies = [
"serde",
"serde_derive",
@@ -3350,9 +3347,9 @@ dependencies = [
[[package]]
name = "cranelift-codegen"
version = "0.116.1"
version = "0.112.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2c22032c4cb42558371cf516bb47f26cdad1819d3475c133e93c49f50ebf304e"
checksum = "709f5567a2bff9f06edf911a7cb5ebb091e4c81701714dc6ab574d08b4a69a0d"
dependencies = [
"bumpalo",
"cranelift-bforest",
@@ -3362,45 +3359,44 @@ dependencies = [
"cranelift-control",
"cranelift-entity",
"cranelift-isle",
"gimli",
"gimli 0.29.0",
"hashbrown 0.14.5",
"log",
"regalloc2",
"rustc-hash 2.1.1",
"serde",
"smallvec",
"target-lexicon 0.13.2",
"target-lexicon",
]
[[package]]
name = "cranelift-codegen-meta"
version = "0.116.1"
version = "0.112.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c904bc71c61b27fc57827f4a1379f29de64fe95653b620a3db77d59655eee0b8"
checksum = "72d39a6b194c069fd091ca1f17b9d86ff1a4627ccad8806095828f61989a691f"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
version = "0.116.1"
version = "0.112.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40180f5497572f644ce88c255480981ae2ec1d7bb4d8e0c0136a13b87a2f2ceb"
checksum = "18f81aefad1f80ed4132ae33f40b92779eeb57edeb1e28bb24424a4098c963a2"
[[package]]
name = "cranelift-control"
version = "0.116.1"
version = "0.112.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d132c6d0bd8a489563472afc171759da0707804a65ece7ceb15a8c6d7dd5ef"
checksum = "6adbaac785ad4683c4f199686f9e15c1471f52ae2f4c013a3be039b4719db754"
dependencies = [
"arbitrary",
]
[[package]]
name = "cranelift-entity"
version = "0.116.1"
version = "0.112.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b2d0d9618275474fbf679dd018ac6e009acbd6ae6850f6a67be33fb3b00b323"
checksum = "70b85ed43567e13782cd1b25baf42a8167ee57169a60dfd3d7307c6ca3839da0"
dependencies = [
"cranelift-bitset",
"serde",
@@ -3409,31 +3405,47 @@ dependencies = [
[[package]]
name = "cranelift-frontend"
version = "0.116.1"
version = "0.112.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fac41e16729107393174b0c9e3730fb072866100e1e64e80a1a963b2e484d57"
checksum = "8349f71373bb69c6f73992c6c1606236a66c8134e7a60e04e03fbd64b1aa7dcf"
dependencies = [
"cranelift-codegen",
"log",
"smallvec",
"target-lexicon 0.13.2",
"target-lexicon",
]
[[package]]
name = "cranelift-isle"
version = "0.116.1"
version = "0.112.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ca20d576e5070044d0a72a9effc2deacf4d6aa650403189d8ea50126483944d"
checksum = "464a6b958ce05e0c237c8b25508012b6c644e8c37348213a8c786ba29e28cfdb"
[[package]]
name = "cranelift-native"
version = "0.116.1"
version = "0.112.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8dee82f3f1f2c4cba9177f1cc5e350fe98764379bcd29340caa7b01f85076c7"
checksum = "ffc4acaf6894ee323ff4e9ce786bec09f0ebbe49941e8012f1c1052f1d965034"
dependencies = [
"cranelift-codegen",
"libc",
"target-lexicon 0.13.2",
"target-lexicon",
]
[[package]]
name = "cranelift-wasm"
version = "0.112.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b878860895cca97454ef8d8b12bfda9d0889dd49efee175dba78d54ff8363ec2"
dependencies = [
"cranelift-codegen",
"cranelift-entity",
"cranelift-frontend",
"itertools 0.12.1",
"log",
"smallvec",
"wasmparser 0.217.1",
"wasmtime-types",
]
[[package]]
@@ -4433,9 +4445,9 @@ dependencies = [
"serde_json",
"toml 0.8.20",
"util",
"wasm-encoder 0.221.3",
"wasmparser 0.221.3",
"wit-component 0.221.3",
"wasm-encoder 0.217.1",
"wasmparser 0.217.1",
"wit-component",
]
[[package]]
@@ -4503,7 +4515,7 @@ dependencies = [
"toml 0.8.20",
"url",
"util",
"wasmparser 0.221.3",
"wasmparser 0.217.1",
"wasmtime",
"wasmtime-wasi",
]
@@ -5251,15 +5263,21 @@ dependencies = [
[[package]]
name = "gimli"
version = "0.31.1"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
dependencies = [
"fallible-iterator",
"indexmap",
"stable_deref_trait",
]
[[package]]
name = "gimli"
version = "0.31.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f"
[[package]]
name = "git"
version = "0.1.0"
@@ -5688,6 +5706,7 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
dependencies = [
"ahash 0.8.11",
"allocator-api2",
"serde",
]
[[package]]
@@ -5699,7 +5718,6 @@ dependencies = [
"allocator-api2",
"equivalent",
"foldhash",
"serde",
]
[[package]]
@@ -6951,7 +6969,6 @@ dependencies = [
"serde_json",
"smol",
"strum",
"thiserror 1.0.69",
"ui",
"util",
]
@@ -6963,7 +6980,6 @@ dependencies = [
"feature_flags",
"gpui",
"language_model",
"log",
"picker",
"proto",
"ui",
@@ -7652,6 +7668,7 @@ dependencies = [
"anyhow",
"assets",
"env_logger 0.11.6",
"futures 0.3.31",
"gpui",
"language",
"languages",
@@ -9759,7 +9776,6 @@ dependencies = [
"serde",
"serde_json",
"ui",
"util",
"workspace",
]
@@ -10432,18 +10448,6 @@ version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3"
[[package]]
name = "pulley-interpreter"
version = "29.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62d95f8575df49a2708398182f49a888cf9dc30210fb1fd2df87c889edcee75d"
dependencies = [
"cranelift-bitset",
"log",
"sptr",
"wasmtime-math",
]
[[package]]
name = "qoi"
version = "0.4.1"
@@ -10824,15 +10828,14 @@ dependencies = [
[[package]]
name = "regalloc2"
version = "0.11.1"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "145c1c267e14f20fb0f88aa76a1c5ffec42d592c1d28b3cd9148ae35916158d3"
checksum = "12908dbeb234370af84d0579b9f68258a0f67e201412dd9a2814e6f45b2fc0f0"
dependencies = [
"allocator-api2",
"bumpalo",
"hashbrown 0.15.2",
"hashbrown 0.14.5",
"log",
"rustc-hash 2.1.1",
"slice-group-by",
"smallvec",
]
@@ -11133,7 +11136,6 @@ dependencies = [
"gpui",
"http_client",
"log",
"regex",
"reqwest 0.12.8",
"serde",
"smol",
@@ -12347,6 +12349,12 @@ dependencies = [
"zed_extension_api 0.1.0",
]
[[package]]
name = "slice-group-by"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826167069c09b99d56f31e9ae5c99049e932a98c9dc2dac47645b08dbbf76ba7"
[[package]]
name = "slotmap"
version = "1.0.7"
@@ -13262,12 +13270,6 @@ version = "0.12.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]]
name = "target-lexicon"
version = "0.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
[[package]]
name = "task"
version = "0.1.0"
@@ -13482,7 +13484,6 @@ dependencies = [
"serde_repr",
"settings",
"strum",
"thiserror 1.0.69",
"util",
"uuid",
]
@@ -14111,27 +14112,15 @@ dependencies = [
"tracing-serde",
]
[[package]]
name = "trait-variant"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.90",
]
[[package]]
name = "tree-sitter"
version = "0.25.2"
version = "0.24.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5168a515fe492af54c5cc8800ff8c840be09fa5168de45838afaecd3e008bce4"
checksum = "a5387dffa7ffc7d2dae12b50c6f7aab8ff79d6210147c6613561fc3d474c6f75"
dependencies = [
"cc",
"regex",
"regex-syntax 0.8.5",
"serde_json",
"streaming-iterator",
"tree-sitter-language",
"wasmtime-c-api-impl",
@@ -14255,12 +14244,12 @@ dependencies = [
[[package]]
name = "tree-sitter-html"
version = "0.23.2"
version = "0.20.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "261b708e5d92061ede329babaaa427b819329a9d427a1d710abb0f67bbef63ee"
checksum = "8766b5ad3721517f8259e6394aefda9c686aebf7a8c74ab8624f2c3b46902fd5"
dependencies = [
"cc",
"tree-sitter-language",
"tree-sitter",
]
[[package]]
@@ -14863,26 +14852,15 @@ dependencies = [
[[package]]
name = "vte"
version = "0.13.1"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a0b683b20ef64071ff03745b14391751f6beab06a54347885459b77a3f2caa5"
checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077"
dependencies = [
"bitflags 2.8.0",
"cursor-icon",
"log",
"memchr",
"serde",
"utf8parse",
"vte_generate_state_changes",
]
[[package]]
name = "vte_generate_state_changes"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
@@ -15043,12 +15021,11 @@ dependencies = [
[[package]]
name = "wasm-encoder"
version = "0.221.3"
version = "0.217.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc8444fe4920de80a4fe5ab564fff2ae58b6b73166b89751f8c6c93509da32e5"
checksum = "10961fd76db420582926af70816dd205019d8152d9e51e1b939125dd1639f854"
dependencies = [
"leb128",
"wasmparser 0.221.3",
]
[[package]]
@@ -15067,22 +15044,6 @@ dependencies = [
"wasmparser 0.201.0",
]
[[package]]
name = "wasm-metadata"
version = "0.221.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11f4ef50d17e103a88774cd4aa5d06bfb1ae44036a8f3f1325e0e9b3e3417ac4"
dependencies = [
"anyhow",
"indexmap",
"serde",
"serde_derive",
"serde_json",
"spdx",
"wasm-encoder 0.221.3",
"wasmparser 0.221.3",
]
[[package]]
name = "wasm-streams"
version = "0.4.2"
@@ -15109,12 +15070,13 @@ dependencies = [
[[package]]
name = "wasmparser"
version = "0.221.3"
version = "0.217.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d06bfa36ab3ac2be0dee563380147a5b81ba10dd8885d7fbbc9eb574be67d185"
checksum = "65a5a0689975b9fd93c02f5400cfd9669858b99607e54e7b892c6080cba598bb"
dependencies = [
"ahash 0.8.11",
"bitflags 2.8.0",
"hashbrown 0.15.2",
"hashbrown 0.14.5",
"indexmap",
"semver",
"serde",
@@ -15122,20 +15084,20 @@ dependencies = [
[[package]]
name = "wasmprinter"
version = "0.221.3"
version = "0.217.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7343c42a97f2926c7819ff81b64012092ae954c5d83ddd30c9fcdefd97d0b283"
checksum = "324c6782d7b81c01625335d252653b26ea68e835ddb4aef4cb1ed3ea40ae3a49"
dependencies = [
"anyhow",
"termcolor",
"wasmparser 0.221.3",
"wasmparser 0.217.1",
]
[[package]]
name = "wasmtime"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11976a250672556d1c4c04c6d5d7656ac9192ac9edc42a4587d6c21460010e69"
checksum = "f38dbf42dc56a6fe41ccd77211ea8ec90855de05e52cd00df5a0a3bca87d6147"
dependencies = [
"anyhow",
"async-trait",
@@ -15147,6 +15109,7 @@ dependencies = [
"hashbrown 0.14.5",
"indexmap",
"libc",
"libm",
"log",
"mach2",
"memfd",
@@ -15155,16 +15118,14 @@ dependencies = [
"paste",
"postcard",
"psm",
"pulley-interpreter",
"rustix",
"semver",
"serde",
"serde_derive",
"smallvec",
"sptr",
"target-lexicon 0.13.2",
"trait-variant",
"wasmparser 0.221.3",
"target-lexicon",
"wasmparser 0.217.1",
"wasmtime-asm-macros",
"wasmtime-component-macro",
"wasmtime-component-util",
@@ -15172,30 +15133,30 @@ dependencies = [
"wasmtime-environ",
"wasmtime-fiber",
"wasmtime-jit-icache-coherence",
"wasmtime-math",
"wasmtime-slab",
"wasmtime-versioned-export-macros",
"wasmtime-winch",
"windows-sys 0.59.0",
"windows-sys 0.52.0",
]
[[package]]
name = "wasmtime-asm-macros"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f178b0d125201fbe9f75beaf849bd3e511891f9e45ba216a5b620802ccf64f2"
checksum = "30e0c7f9983c2d60109a939d9ab0e0df301901085c3608e1c22c27c98390a027"
dependencies = [
"cfg-if",
]
[[package]]
name = "wasmtime-c-api-impl"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea30cef3608f2de5797c7bbb94c1ba4f3676d9a7f81ae86ced1b512e2766ed0c"
checksum = "ebfcdb4aa0f68020934099815cf6ef11dbbedaf070ef800b3f0a7f6ec7b7d005"
dependencies = [
"anyhow",
"log",
"once_cell",
"tracing",
"wasmtime",
"wasmtime-c-api-macros",
@@ -15203,9 +15164,9 @@ dependencies = [
[[package]]
name = "wasmtime-c-api-macros"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "022a79ebe1124d5d384d82463d7e61c6b4dd857d81f15cb8078974eeb86db65b"
checksum = "842c213ad4546fb0178735910b96ee7da303e1d745c3f42f4178b0de1da138b6"
dependencies = [
"proc-macro2",
"quote",
@@ -15213,9 +15174,9 @@ dependencies = [
[[package]]
name = "wasmtime-component-macro"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d74de6592ed945d0a602f71243982a304d5d02f1e501b638addf57f42d57dfaf"
checksum = "0929ffffaca32dd8770b56848c94056036963ca05de25fb47cac644e20262168"
dependencies = [
"anyhow",
"proc-macro2",
@@ -15223,20 +15184,20 @@ dependencies = [
"syn 2.0.90",
"wasmtime-component-util",
"wasmtime-wit-bindgen",
"wit-parser 0.221.3",
"wit-parser 0.217.1",
]
[[package]]
name = "wasmtime-component-util"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "707dc7b3c112ab5a366b30cfe2fb5b2f8e6a0f682f16df96a5ec582bfe6f056e"
checksum = "fdc29d2b56629d66d2fd791d1b46471d0016e0d684ed2dc299e870d127082268"
[[package]]
name = "wasmtime-cranelift"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "366be722674d4bf153290fbcbc4d7d16895cc82fb3e869f8d550ff768f9e9e87"
checksum = "f8c8af1197703f4de556a274384adf5db36a146f9892bc9607bad16881e75c80"
dependencies = [
"anyhow",
"cfg-if",
@@ -15245,29 +15206,29 @@ dependencies = [
"cranelift-entity",
"cranelift-frontend",
"cranelift-native",
"gimli",
"itertools 0.12.1",
"cranelift-wasm",
"gimli 0.29.0",
"log",
"object",
"smallvec",
"target-lexicon 0.13.2",
"target-lexicon",
"thiserror 1.0.69",
"wasmparser 0.221.3",
"wasmparser 0.217.1",
"wasmtime-environ",
"wasmtime-versioned-export-macros",
]
[[package]]
name = "wasmtime-environ"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdadc1af7097347aa276a4f008929810f726b5b46946971c660b6d421e9994ad"
checksum = "3f1b5af7bac868c5bce3b78a366a10677caacf6e6467c156301297e36ed31f3e"
dependencies = [
"anyhow",
"cpp_demangle",
"cranelift-bitset",
"cranelift-entity",
"gimli",
"gimli 0.29.0",
"indexmap",
"log",
"object",
@@ -15276,19 +15237,19 @@ dependencies = [
"semver",
"serde",
"serde_derive",
"smallvec",
"target-lexicon 0.13.2",
"wasm-encoder 0.221.3",
"wasmparser 0.221.3",
"target-lexicon",
"wasm-encoder 0.217.1",
"wasmparser 0.217.1",
"wasmprinter",
"wasmtime-component-util",
"wasmtime-types",
]
[[package]]
name = "wasmtime-fiber"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ccba90d4119f081bca91190485650730a617be1fff5228f8c4757ce133d21117"
checksum = "665ccc1bb0f28496e6fa02e94c575ee9ad6e3202c7df8591e5dda78106d5aa4a"
dependencies = [
"anyhow",
"cc",
@@ -15296,41 +15257,46 @@ dependencies = [
"rustix",
"wasmtime-asm-macros",
"wasmtime-versioned-export-macros",
"windows-sys 0.59.0",
"windows-sys 0.52.0",
]
[[package]]
name = "wasmtime-jit-icache-coherence"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec5e8552e01692e6c2e5293171704fed8abdec79d1a6995a0870ab190e5747d1"
checksum = "5d7314e32c624f645ad7d6b9fc3ac89eb7d2b9aa06695d6445cec087958ec27d"
dependencies = [
"anyhow",
"cfg-if",
"libc",
"windows-sys 0.59.0",
]
[[package]]
name = "wasmtime-math"
version = "29.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29210ec2aa25e00f4d54605cedaf080f39ec01a872c5bd520ad04c67af1dde17"
dependencies = [
"libm",
"windows-sys 0.52.0",
]
[[package]]
name = "wasmtime-slab"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcb5821a96fa04ac14bc7b158bb3d5cd7729a053db5a74dad396cd513a5e5ccf"
checksum = "f75cba1a8cc327839f493cfc3036c9de3d077d59ab76296bc710ee5f95be5391"
[[package]]
name = "wasmtime-types"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6d83a7816947a4974e2380c311eacb1db009b8bad86081dc726b705603c93c7"
dependencies = [
"anyhow",
"cranelift-entity",
"serde",
"serde_derive",
"smallvec",
"wasmparser 0.217.1",
]
[[package]]
name = "wasmtime-versioned-export-macros"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "86ff86db216dc0240462de40c8290887a613dddf9685508eb39479037ba97b5b"
checksum = "6879a8e168aef3fe07335343b7fbede12fa494215e83322e173d4018e124a846"
dependencies = [
"proc-macro2",
"quote",
@@ -15339,9 +15305,9 @@ dependencies = [
[[package]]
name = "wasmtime-wasi"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d1be69bfcab1bdac74daa7a1f9695ab992b9c8e21b9b061e7d66434097e0ca4"
checksum = "d042ea66b2834fb03b8a6968ef1a99a4b537211b00f7502a4d6a37f4eb2049b2"
dependencies = [
"anyhow",
"async-trait",
@@ -15356,30 +15322,30 @@ dependencies = [
"futures 0.3.31",
"io-extras",
"io-lifetimes",
"once_cell",
"rustix",
"system-interface",
"thiserror 1.0.69",
"tokio",
"tracing",
"trait-variant",
"url",
"wasmtime",
"wiggle",
"windows-sys 0.59.0",
"windows-sys 0.52.0",
]
[[package]]
name = "wasmtime-winch"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdbabfb8f20502d5e1d81092b9ead3682ae59988487aafcd7567387b7a43cf8f"
checksum = "6baca2a919a288df653246069868b4de80f07e9679a8ef9b78ad79fc658ffd12"
dependencies = [
"anyhow",
"cranelift-codegen",
"gimli",
"gimli 0.29.0",
"object",
"target-lexicon 0.13.2",
"wasmparser 0.221.3",
"target-lexicon",
"wasmparser 0.217.1",
"wasmtime-cranelift",
"wasmtime-environ",
"winch-codegen",
@@ -15387,14 +15353,14 @@ dependencies = [
[[package]]
name = "wasmtime-wit-bindgen"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8358319c2dd1e4db79e3c1c5d3a5af84956615343f9f89f4e4996a36816e06e6"
checksum = "3f571f63ac1d532e986eb3973bbef3a45e4ae83de521a8d573b0fe0594dc9608"
dependencies = [
"anyhow",
"heck 0.5.0",
"heck 0.4.1",
"indexmap",
"wit-parser 0.221.3",
"wit-parser 0.217.1",
]
[[package]]
@@ -15622,9 +15588,9 @@ dependencies = [
[[package]]
name = "wiggle"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b9af35bc9629c52c261465320a9a07959164928b4241980ba1cf923b9e6751d"
checksum = "4c8fdcd81702e0f46a8ab2ed28a5bf824aabf4a1af1673af496a020aacd0b6f9"
dependencies = [
"anyhow",
"async-trait",
@@ -15637,12 +15603,12 @@ dependencies = [
[[package]]
name = "wiggle-generate"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cf267dd05673912c8138f4b54acabe6bd53407d9d1536f0fadb6520dd16e101"
checksum = "14f745361f0a9071aaabd05de1bb2b782d9f0597f30d9c0f20326224902e64d5"
dependencies = [
"anyhow",
"heck 0.5.0",
"heck 0.4.1",
"proc-macro2",
"quote",
"shellexpand 2.1.2",
@@ -15652,9 +15618,9 @@ dependencies = [
[[package]]
name = "wiggle-macro"
version = "29.0.1"
version = "25.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08c5c473d4198e6c2d377f3809f713ff0c110cab88a0805ae099a82119ee250c"
checksum = "bfbdae3574621921ed3c13325edc910388487759d10fb330f656cfc69bee38db"
dependencies = [
"proc-macro2",
"quote",
@@ -15695,18 +15661,17 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "winch-codegen"
version = "29.0.1"
version = "0.23.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f849ef2c5f46cb0a20af4b4487aaa239846e52e2c03f13fa3c784684552859c"
checksum = "01cd1dc56c5a45d509ff06e7ca8817eaa9ec3240096f07e71915d5d528658e8a"
dependencies = [
"anyhow",
"cranelift-codegen",
"gimli",
"gimli 0.29.0",
"regalloc2",
"smallvec",
"target-lexicon 0.13.2",
"thiserror 1.0.69",
"wasmparser 0.221.3",
"target-lexicon",
"wasmparser 0.217.1",
"wasmtime-cranelift",
"wasmtime-environ",
]
@@ -16200,9 +16165,9 @@ dependencies = [
"anyhow",
"heck 0.4.1",
"indexmap",
"wasm-metadata 0.201.0",
"wasm-metadata",
"wit-bindgen-core",
"wit-component 0.201.0",
"wit-component",
]
[[package]]
@@ -16233,30 +16198,11 @@ dependencies = [
"serde_derive",
"serde_json",
"wasm-encoder 0.201.0",
"wasm-metadata 0.201.0",
"wasm-metadata",
"wasmparser 0.201.0",
"wit-parser 0.201.0",
]
[[package]]
name = "wit-component"
version = "0.221.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66c55ca8772d2b270e28066caed50ce4e53a28c3ac10e01efbd90e5be31e448b"
dependencies = [
"anyhow",
"bitflags 2.8.0",
"indexmap",
"log",
"serde",
"serde_derive",
"serde_json",
"wasm-encoder 0.221.3",
"wasm-metadata 0.221.3",
"wasmparser 0.221.3",
"wit-parser 0.221.3",
]
[[package]]
name = "wit-parser"
version = "0.201.0"
@@ -16277,9 +16223,9 @@ dependencies = [
[[package]]
name = "wit-parser"
version = "0.221.3"
version = "0.217.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "896112579ed56b4a538b07a3d16e562d101ff6265c46b515ce0c701eef16b2ac"
checksum = "e5aaf02882453eaeec4fe30f1e4263cfd8b8ea36dd00e1fe7d902d9cb498bccd"
dependencies = [
"anyhow",
"id-arena",
@@ -16290,7 +16236,7 @@ dependencies = [
"serde_derive",
"serde_json",
"unicode-xid",
"wasmparser 0.221.3",
"wasmparser 0.217.1",
]
[[package]]

View File

@@ -364,7 +364,8 @@ zeta = { path = "crates/zeta" }
#
aho-corasick = "1.1"
alacritty_terminal = "0.25"
# TODO(#18342): Update to version 0.25 from crates.io when it is released.
alacritty_terminal = { git = "https://github.com/alacritty/alacritty.git", rev = "5e78d20c709cb1ab8d44ca7a8702cc26d779227c" }
any_vec = "0.14"
anyhow = "1.0.86"
arrayvec = { version = "0.7.4", features = ["serde"] }
@@ -526,7 +527,7 @@ tiny_http = "0.8"
toml = "0.8"
tokio = { version = "1" }
tower-http = "0.4.4"
tree-sitter = { version = "0.25.2", features = ["wasm"] }
tree-sitter = { version = "0.24", features = ["wasm"] }
tree-sitter-bash = "0.23"
tree-sitter-c = "0.23"
tree-sitter-cpp = "0.23"
@@ -539,7 +540,7 @@ tree-sitter-go-mod = { git = "https://github.com/camdencheek/tree-sitter-go-mod"
tree-sitter-gowork = { git = "https://github.com/zed-industries/tree-sitter-go-work", rev = "acb0617bf7f4fda02c6217676cc64acb89536dc7" }
tree-sitter-heex = { git = "https://github.com/zed-industries/tree-sitter-heex", rev = "1dd45142fbb05562e35b2040c6129c9bca346592" }
tree-sitter-diff = "0.1.0"
tree-sitter-html = "0.23"
tree-sitter-html = "0.20"
tree-sitter-jsdoc = "0.23"
tree-sitter-json = "0.24"
tree-sitter-md = { git = "https://github.com/tree-sitter-grammars/tree-sitter-markdown", rev = "9a23c1a96c0513d8fc6520972beedd419a973539" }
@@ -555,18 +556,18 @@ unicode-segmentation = "1.10"
unicode-script = "0.5.7"
url = "2.2"
uuid = { version = "1.1.2", features = ["v4", "v5", "v7", "serde"] }
wasmparser = "0.221"
wasm-encoder = "0.221"
wasmtime = { version = "29", default-features = false, features = [
wasmparser = "0.217"
wasm-encoder = "0.217"
wasmtime = { version = "25", default-features = false, features = [
"async",
"demangle",
"runtime",
"cranelift",
"component-model",
] }
wasmtime-wasi = "29"
wasmtime-wasi = "25"
which = "6.0.0"
wit-component = "0.221"
wit-component = "0.201"
zed_llm_client = "0.4"
zstd = "0.11"
metal = "0.31"
@@ -701,7 +702,6 @@ codegen-units = 16
[workspace.lints.clippy]
dbg_macro = "deny"
todo = "deny"
too_many_arguments = "allow"
# Motivation: We use `vec![a..b]` a lot when dealing with ranges in text, so
# warning on this rule produces a lot of noise.

View File

@@ -587,7 +587,6 @@
"save": "workspace::Save",
"ctrl->": "assistant::QuoteSelection",
"ctrl-<": "assistant::InsertIntoEditor",
"ctrl-alt-/": "assistant::ToggleModelSelector",
"shift-enter": "assistant::Split",
"ctrl-r": "assistant::CycleMessageRole",
"enter": "assistant::ConfirmCommand",
@@ -767,7 +766,13 @@
}
},
{
"context": "FileFinder || (FileFinder > Picker > Editor) || (FileFinder > Picker > menu)",
"context": "FileFinder",
"bindings": {
"ctrl": "file_finder::ToggleMenu"
}
},
{
"context": "FileFinder && !menu_open",
"bindings": {
"ctrl-shift-p": "file_finder::SelectPrev",
"ctrl-j": "pane::SplitDown",
@@ -776,6 +781,15 @@
"ctrl-l": "pane::SplitRight"
}
},
{
"context": "FileFinder && menu_open",
"bindings": {
"j": "pane::SplitDown",
"k": "pane::SplitUp",
"h": "pane::SplitLeft",
"l": "pane::SplitRight"
}
},
{
"context": "TabSwitcher",
"bindings": {

View File

@@ -218,7 +218,6 @@
"cmd-s": "workspace::Save",
"cmd->": "assistant::QuoteSelection",
"cmd-<": "assistant::InsertIntoEditor",
"cmd-alt-/": "assistant::ToggleModelSelector",
"shift-enter": "assistant::Split",
"ctrl-r": "assistant::CycleMessageRole",
"enter": "assistant::ConfirmCommand",
@@ -785,7 +784,14 @@
}
},
{
"context": "FileFinder || (FileFinder > Picker > Editor) || (FileFinder > Picker > menu)",
"context": "FileFinder",
"use_key_equivalents": true,
"bindings": {
"cmd": "file_finder::ToggleMenu"
}
},
{
"context": "FileFinder && !menu_open",
"use_key_equivalents": true,
"bindings": {
"cmd-shift-p": "file_finder::SelectPrev",
@@ -795,6 +801,16 @@
"cmd-l": "pane::SplitRight"
}
},
{
"context": "FileFinder && menu_open",
"use_key_equivalents": true,
"bindings": {
"j": "pane::SplitDown",
"k": "pane::SplitUp",
"h": "pane::SplitLeft",
"l": "pane::SplitRight"
}
},
{
"context": "TabSwitcher",
"use_key_equivalents": true,

View File

@@ -154,10 +154,6 @@
// 4. Highlight the full line (default):
// "all"
"current_line_highlight": "all",
// Whether to highlight all occurrences of the selected text in an editor.
"selection_highlight": true,
// The debounce delay before querying highlights based on the selected text.
"selection_highlight_debounce": 50,
// The debounce delay before querying highlights from the language
// server based on the current cursor location.
"lsp_highlight_debounce": 75,
@@ -263,8 +259,6 @@
"git_diff": true,
// Whether to show buffer search results in the scrollbar.
"search_results": true,
// Whether to show selected text occurrences in the scrollbar.
"selected_text": true,
// Whether to show selected symbol occurrences in the scrollbar.
"selected_symbol": true,
// Which diagnostic indicators to show in the scrollbar:
@@ -736,8 +730,9 @@
// Whether to show warnings or not by default.
"include_warnings": true
},
// Files or globs of files that will be excluded by Zed entirely. They will be skipped during file
// scans, file searches, and not be displayed in the project file tree. Takes precedence over `file_scan_inclusions`.
// Add files or globs of files that will be excluded by Zed entirely:
// they will be skipped during FS scan(s), file tree and file search
// will lack the corresponding file entries. Overrides `file_scan_inclusions`.
"file_scan_exclusions": [
"**/.git",
"**/.svn",
@@ -749,10 +744,10 @@
"**/.classpath",
"**/.settings"
],
// Files or globs of files that will be included by Zed, even when ignored by git. This is useful
// for files that are not tracked by git, but are still important to your project. Note that globs
// that are overly broad can slow down Zed's file scanning. `file_scan_exclusions` takes
// precedence over these inclusions.
// Add files or globs of files that will be included by Zed, even when
// ignored by git. This is useful for files that are not tracked by git,
// but are still important to your project. Note that globs that are
// overly broad can slow down Zed's file scanning. Overridden by `file_scan_exclusions`.
"file_scan_inclusions": [".env*"],
// Git gutter behavior configuration.
"git": {

View File

@@ -105,6 +105,16 @@
"terminal.ansi.bright_white": "#fbf1c7ff",
"terminal.ansi.dim_white": "#b0a189ff",
"link_text.hover": "#83a598ff",
"version_control.added": "#b7bb26ff",
"version_control.added_background": "#b7bb2614",
"version_control.deleted": "#fb4a35ff",
"version_control.deleted_background": "#fb4a3514",
"version_control.modified": "#f9bd2fff",
"version_control.modified_background": "#f9bd2f14",
"version_control.renamed": "#83a598ff",
"version_control.conflict": "#f9bd2fff",
"version_control.conflict_background": "#f9bd2f14",
"version_control.ignored": "#998b78ff",
"conflict": "#f9bd2fff",
"conflict.background": "#572e10ff",
"conflict.border": "#754916ff",
@@ -490,6 +500,16 @@
"terminal.ansi.bright_white": "#fbf1c7ff",
"terminal.ansi.dim_white": "#b0a189ff",
"link_text.hover": "#83a598ff",
"version_control.added": "#b7bb26ff",
"version_control.added_background": "#b7bb2614",
"version_control.deleted": "#fb4a35ff",
"version_control.deleted_background": "#fb4a3514",
"version_control.modified": "#f9bd2fff",
"version_control.modified_background": "#f9bd2f14",
"version_control.renamed": "#83a598ff",
"version_control.conflict": "#f9bd2fff",
"version_control.conflict_background": "#f9bd2f14",
"version_control.ignored": "#998b78ff",
"conflict": "#f9bd2fff",
"conflict.background": "#572e10ff",
"conflict.border": "#754916ff",
@@ -875,6 +895,16 @@
"terminal.ansi.bright_white": "#fbf1c7ff",
"terminal.ansi.dim_white": "#b0a189ff",
"link_text.hover": "#83a598ff",
"version_control.added": "#b7bb26ff",
"version_control.added_background": "#b7bb2614",
"version_control.deleted": "#fb4a35ff",
"version_control.deleted_background": "#fb4a3514",
"version_control.modified": "#f9bd2fff",
"version_control.modified_background": "#f9bd2f14",
"version_control.renamed": "#83a598ff",
"version_control.conflict": "#f9bd2fff",
"version_control.conflict_background": "#f9bd2f14",
"version_control.ignored": "#998b78ff",
"conflict": "#f9bd2fff",
"conflict.background": "#572e10ff",
"conflict.border": "#754916ff",
@@ -1260,6 +1290,16 @@
"terminal.ansi.bright_white": "#282828ff",
"terminal.ansi.dim_white": "#73675eff",
"link_text.hover": "#0b6678ff",
"version_control.added": "#79740eff",
"version_control.added_background": "#79740e14",
"version_control.deleted": "#9d0006ff",
"version_control.deleted_background": "#9d000614",
"version_control.modified": "#b57614ff",
"version_control.modified_background": "#b5761414",
"version_control.renamed": "#076678ff",
"version_control.conflict": "#b57614ff",
"version_control.conflict_background": "#b5761414",
"version_control.ignored": "#928374ff",
"conflict": "#b57615ff",
"conflict.background": "#f5e2d0ff",
"conflict.border": "#ebccabff",
@@ -1645,6 +1685,16 @@
"terminal.ansi.bright_white": "#282828ff",
"terminal.ansi.dim_white": "#73675eff",
"link_text.hover": "#0b6678ff",
"version_control.added": "#79740eff",
"version_control.added_background": "#79740e14",
"version_control.deleted": "#9d0006ff",
"version_control.deleted_background": "#9d000614",
"version_control.modified": "#b57614ff",
"version_control.modified_background": "#b5761414",
"version_control.renamed": "#076678ff",
"version_control.conflict": "#b57614ff",
"version_control.conflict_background": "#b5761414",
"version_control.ignored": "#928374ff",
"conflict": "#b57615ff",
"conflict.background": "#f5e2d0ff",
"conflict.border": "#ebccabff",
@@ -2030,6 +2080,16 @@
"terminal.ansi.bright_white": "#282828ff",
"terminal.ansi.dim_white": "#73675eff",
"link_text.hover": "#0b6678ff",
"version_control.added": "#79740eff",
"version_control.added_background": "#79740e14",
"version_control.deleted": "#9d0006ff",
"version_control.deleted_background": "#9d000614",
"version_control.modified": "#b57614ff",
"version_control.modified_background": "#b5761414",
"version_control.renamed": "#076678ff",
"version_control.conflict": "#b57614ff",
"version_control.conflict_background": "#b5761414",
"version_control.ignored": "#928374ff",
"conflict": "#b57615ff",
"conflict.background": "#f5e2d0ff",
"conflict.border": "#ebccabff",

View File

@@ -96,6 +96,16 @@
"terminal.ansi.bright_white": "#dce0e5ff",
"terminal.ansi.dim_white": "#575d65ff",
"link_text.hover": "#74ade8ff",
"version_control.added": "#a1c181ff",
"version_control.added_background": "#a1c18114",
"version_control.deleted": "#d07277ff",
"version_control.deleted_background": "#d0727714",
"version_control.modified": "#dec184ff",
"version_control.modified_background": "#dec18414",
"version_control.renamed": "#74ade8ff",
"version_control.conflict": "#dec184ff",
"version_control.conflict_background": "#dec18414",
"version_control.ignored": "#878a98ff",
"conflict": "#dec184ff",
"conflict.background": "#dec1841a",
"conflict.border": "#5d4c2fff",
@@ -441,7 +451,7 @@
"editor.invisible": "#a3a3a4ff",
"editor.wrap_guide": "#383a410d",
"editor.active_wrap_guide": "#383a411a",
"editor.document_highlight.read_background": "#5c78e225",
"editor.document_highlight.read_background": "#5c78e21a",
"editor.document_highlight.write_background": "#a3a3a466",
"terminal.background": "#fafafaff",
"terminal.foreground": "#242529ff",

View File

@@ -7,7 +7,7 @@ use assistant_context_editor::{
make_lsp_adapter_delegate, AssistantContext, AssistantPanelDelegate, ContextEditor,
ContextEditorToolbarItem, ContextEditorToolbarItemEvent, ContextHistory, ContextId,
ContextStore, ContextStoreEvent, InsertDraggedFiles, SlashCommandCompletionProvider,
DEFAULT_TAB_TITLE,
ToggleModelSelector, DEFAULT_TAB_TITLE,
};
use assistant_settings::{AssistantDockPosition, AssistantSettings};
use assistant_slash_command::SlashCommandWorkingSet;
@@ -20,9 +20,8 @@ use gpui::{
Subscription, Task, UpdateGlobal, WeakEntity,
};
use language::LanguageRegistry;
use language_model::{
AuthenticateError, LanguageModelProviderId, LanguageModelRegistry, ZED_CLOUD_PROVIDER_ID,
};
use language_model::{LanguageModelProviderId, LanguageModelRegistry, ZED_CLOUD_PROVIDER_ID};
use language_model_selector::LanguageModelSelector;
use project::Project;
use prompt_library::{open_prompt_library, PromptBuilder, PromptLibrary};
use search::{buffer_search::DivRegistrar, BufferSearchBar};
@@ -30,7 +29,7 @@ use settings::{update_settings_file, Settings};
use smol::stream::StreamExt;
use std::{ops::ControlFlow, path::PathBuf, sync::Arc};
use terminal_view::{terminal_panel::TerminalPanel, TerminalView};
use ui::{prelude::*, ContextMenu, PopoverMenu, Tooltip};
use ui::{prelude::*, ContextMenu, PopoverMenu, PopoverMenuHandle, Tooltip};
use util::{maybe, ResultExt};
use workspace::DraggedTab;
use workspace::{
@@ -78,6 +77,7 @@ pub struct AssistantPanel {
languages: Arc<LanguageRegistry>,
fs: Arc<dyn Fs>,
subscriptions: Vec<Subscription>,
model_selector_menu_handle: PopoverMenuHandle<LanguageModelSelector>,
model_summary_editor: Entity<Editor>,
authenticate_provider_task: Option<(LanguageModelProviderId, Task<()>)>,
configuration_subscription: Option<Subscription>,
@@ -119,9 +119,17 @@ impl AssistantPanel {
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
let model_selector_menu_handle = PopoverMenuHandle::default();
let model_summary_editor = cx.new(|cx| Editor::single_line(window, cx));
let context_editor_toolbar =
cx.new(|_| ContextEditorToolbarItem::new(model_summary_editor.clone()));
let context_editor_toolbar = cx.new(|cx| {
ContextEditorToolbarItem::new(
workspace,
model_selector_menu_handle.clone(),
model_summary_editor.clone(),
window,
cx,
)
});
let pane = cx.new(|cx| {
let mut pane = Pane::new(
@@ -323,6 +331,7 @@ impl AssistantPanel {
languages: workspace.app_state().languages.clone(),
fs: workspace.app_state().fs.clone(),
subscriptions,
model_selector_menu_handle,
model_summary_editor,
authenticate_provider_task: None,
configuration_subscription: None,
@@ -1045,6 +1054,15 @@ impl AssistantPanel {
.detach_and_log_err(cx);
}
fn toggle_model_selector(
&mut self,
_: &ToggleModelSelector,
window: &mut Window,
cx: &mut Context<Self>,
) {
self.model_selector_menu_handle.toggle(window, cx);
}
pub(crate) fn active_context_editor(&self, cx: &App) -> Option<Entity<ContextEditor>> {
self.pane
.read(cx)
@@ -1158,10 +1176,7 @@ impl AssistantPanel {
.map_or(false, |provider| provider.is_authenticated(cx))
}
fn authenticate(
&mut self,
cx: &mut Context<Self>,
) -> Option<Task<Result<(), AuthenticateError>>> {
fn authenticate(&mut self, cx: &mut Context<Self>) -> Option<Task<Result<()>>> {
LanguageModelRegistry::read_global(cx)
.active_provider()
.map_or(None, |provider| Some(provider.authenticate(cx)))
@@ -1214,6 +1229,7 @@ impl Render for AssistantPanel {
}))
.on_action(cx.listener(AssistantPanel::deploy_history))
.on_action(cx.listener(AssistantPanel::deploy_prompt_library))
.on_action(cx.listener(AssistantPanel::toggle_model_selector))
.child(registrar.size_full().child(self.pane.clone()))
.into_any_element()
}

View File

@@ -387,6 +387,7 @@ impl InlineAssistant {
}
}
#[allow(clippy::too_many_arguments)]
pub fn suggest_assist(
&mut self,
editor: &Entity<Editor>,
@@ -1610,7 +1611,6 @@ impl Render for PromptEditor {
cx,
)
},
gpui::Corner::TopRight,
))
.map(|el| {
let CodegenStatus::Error(error) = self.codegen.read(cx).status(cx) else {
@@ -1674,6 +1674,7 @@ impl Focusable for PromptEditor {
impl PromptEditor {
const MAX_LINES: u8 = 8;
#[allow(clippy::too_many_arguments)]
fn new(
id: InlineAssistId,
gutter_dimensions: Arc<Mutex<GutterDimensions>>,
@@ -2332,6 +2333,7 @@ struct InlineAssist {
}
impl InlineAssist {
#[allow(clippy::too_many_arguments)]
fn new(
assist_id: InlineAssistId,
group_id: InlineAssistGroupId,
@@ -3013,7 +3015,7 @@ impl CodegenAlternative {
let executor = cx.background_executor().clone();
let message_id = message_id.clone();
let line_based_stream_diff: Task<anyhow::Result<()>> =
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let mut response_latency = None;
let request_start = Instant::now();
let diff = async {
@@ -3327,7 +3329,8 @@ impl CodegenAlternative {
cx.spawn(|codegen, mut cx| async move {
let (deleted_row_ranges, inserted_row_ranges) = cx
.background_spawn(async move {
.background_executor()
.spawn(async move {
let old_text = old_snapshot
.text_for_range(
Point::new(old_range.start.row, 0)

View File

@@ -662,7 +662,6 @@ impl Render for PromptEditor {
cx,
)
},
gpui::Corner::TopRight,
))
.children(
if let CodegenStatus::Error(error) = &self.codegen.read(cx).status {
@@ -702,6 +701,7 @@ impl Focusable for PromptEditor {
impl PromptEditor {
const MAX_LINES: u8 = 8;
#[allow(clippy::too_many_arguments)]
fn new(
id: TerminalInlineAssistId,
prompt_history: VecDeque<String>,
@@ -1150,7 +1150,7 @@ impl Codegen {
let (mut hunks_tx, mut hunks_rx) = mpsc::channel(1);
let task = cx.background_spawn({
let task = cx.background_executor().spawn({
let message_id = message_id.clone();
let executor = cx.background_executor().clone();
async move {

View File

@@ -179,7 +179,7 @@ impl ActiveThread {
let markdown = cx.new(|cx| {
Markdown::new(
text.into(),
text,
markdown_style,
Some(self.language_registry.clone()),
None,

View File

@@ -66,7 +66,6 @@ pub fn init(
cx: &mut App,
) {
AssistantSettings::register(cx);
thread_store::init(cx);
assistant_panel::init(cx);
inline_assistant::init(

View File

@@ -61,9 +61,13 @@ impl Render for AssistantModelSelector {
h_flex()
.gap_0p5()
.child(
Label::new(model_name)
.size(LabelSize::Small)
.color(Color::Muted),
div().max_w_32().child(
Label::new(model_name)
.size(LabelSize::Small)
.color(Color::Muted)
.text_ellipsis()
.into_any_element(),
),
)
.child(
Icon::new(IconName::ChevronDown)
@@ -80,7 +84,6 @@ impl Render for AssistantModelSelector {
cx,
)
},
gpui::Corner::BottomRight,
)
.with_handle(self.menu_handle.clone())
}

View File

@@ -3,8 +3,8 @@ use std::sync::Arc;
use anyhow::{anyhow, Result};
use assistant_context_editor::{
make_lsp_adapter_delegate, render_remaining_tokens, AssistantPanelDelegate, ConfigurationError,
ContextEditor, ContextHistory, SlashCommandCompletionProvider,
make_lsp_adapter_delegate, AssistantPanelDelegate, ConfigurationError, ContextEditor,
ContextHistory, SlashCommandCompletionProvider,
};
use assistant_settings::{AssistantDockPosition, AssistantSettings};
use assistant_slash_command::SlashCommandWorkingSet;
@@ -323,9 +323,6 @@ impl AssistantPanel {
}
fn open_history(&mut self, window: &mut Window, cx: &mut Context<Self>) {
self.thread_store
.update(cx, |thread_store, cx| thread_store.reload(cx))
.detach_and_log_err(cx);
self.active_view = ActiveView::History;
self.history.focus_handle(cx).focus(window);
cx.notify();
@@ -481,10 +478,6 @@ impl AssistantPanel {
.update(cx, |this, cx| this.delete_thread(thread_id, cx))
.detach_and_log_err(cx);
}
pub(crate) fn active_context_editor(&self) -> Option<Entity<ContextEditor>> {
self.context_editor.clone()
}
}
impl Focusable for AssistantPanel {
@@ -642,33 +635,20 @@ impl AssistantPanel {
.border_color(cx.theme().colors().border)
.child(
h_flex()
.w_full()
.gap_1()
.justify_between()
.child(
h_flex()
.child(Label::new(title))
.when(sub_title.is_some(), |this| {
this.child(
h_flex()
.pl_1p5()
.gap_1p5()
.child(
Label::new("/")
.size(LabelSize::Small)
.color(Color::Disabled)
.alpha(0.5),
)
.child(Label::new(sub_title.unwrap())),
.child(Label::new(title))
.when(sub_title.is_some(), |this| {
this.child(
h_flex()
.pl_1p5()
.gap_1p5()
.child(
Label::new("/")
.size(LabelSize::Small)
.color(Color::Disabled)
.alpha(0.5),
)
}),
)
.children(if matches!(self.active_view, ActiveView::PromptEditor) {
self.context_editor
.as_ref()
.and_then(|editor| render_remaining_tokens(editor, cx))
} else {
None
.child(Label::new(sub_title.unwrap())),
)
}),
)
.child(

View File

@@ -493,7 +493,7 @@ impl CodegenAlternative {
let executor = cx.background_executor().clone();
let message_id = message_id.clone();
let line_based_stream_diff: Task<anyhow::Result<()>> =
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let mut response_latency = None;
let request_start = Instant::now();
let diff = async {
@@ -807,7 +807,8 @@ impl CodegenAlternative {
cx.spawn(|codegen, mut cx| async move {
let (deleted_row_ranges, inserted_row_ranges) = cx
.background_spawn(async move {
.background_executor()
.spawn(async move {
let old_text = old_snapshot
.text_for_range(
Point::new(old_range.start.row, 0)

View File

@@ -208,7 +208,8 @@ impl PickerDelegate for FetchContextPickerDelegate {
let confirm_behavior = self.confirm_behavior;
cx.spawn_in(window, |this, mut cx| async move {
let text = cx
.background_spawn(Self::build_message(http_client, url.clone()))
.background_executor()
.spawn(Self::build_message(http_client, url.clone()))
.await?;
this.update_in(&mut cx, |this, window, cx| {

View File

@@ -288,11 +288,8 @@ impl PickerDelegate for FileContextPickerDelegate {
editor.insert("\n", window, cx); // Needed to end the fold
let file_icon = FileIcons::get_icon(&Path::new(&full_path), cx)
.unwrap_or_else(|| SharedString::new(""));
let placeholder = FoldPlaceholder {
render: render_fold_icon_button(file_icon, file_name.into()),
render: render_fold_icon_button(IconName::File, file_name.into()),
..Default::default()
};
@@ -462,27 +459,15 @@ pub fn render_file_context_entry(
}
fn render_fold_icon_button(
icon: SharedString,
icon: IconName,
label: SharedString,
) -> Arc<dyn Send + Sync + Fn(FoldId, Range<Anchor>, &mut Window, &mut App) -> AnyElement> {
Arc::new(move |fold_id, _fold_range, _window, _cx| {
ButtonLike::new(fold_id)
.style(ButtonStyle::Filled)
.layer(ElevationIndex::ElevatedSurface)
.child(
h_flex()
.gap_1()
.child(
Icon::from_path(icon.clone())
.size(IconSize::Small)
.color(Color::Muted),
)
.child(
Label::new(label.clone())
.size(LabelSize::Small)
.single_line(),
),
)
.child(Icon::new(icon))
.child(Label::new(label.clone()).single_line())
.into_any_element()
})
}

View File

@@ -123,7 +123,7 @@ impl PickerDelegate for ThreadContextPickerDelegate {
};
let executor = cx.background_executor().clone();
let search_task = cx.background_spawn(async move {
let search_task = cx.background_executor().spawn(async move {
if query.is_empty() {
threads
} else {

View File

@@ -4,7 +4,7 @@ use std::sync::Arc;
use anyhow::{anyhow, bail, Result};
use collections::{BTreeMap, HashMap, HashSet};
use futures::{self, future, Future, FutureExt};
use gpui::{App, AppContext as _, AsyncApp, Context, Entity, SharedString, Task, WeakEntity};
use gpui::{App, AsyncApp, Context, Entity, SharedString, Task, WeakEntity};
use language::Buffer;
use project::{ProjectPath, Worktree};
use rope::Rope;
@@ -456,7 +456,9 @@ fn collect_buffer_info_and_text(
};
// Important to collect version at the same time as content so that staleness logic is correct.
let content = buffer.as_rope().clone();
let text_task = cx.background_spawn(async move { to_fenced_codeblock(&path, content) });
let text_task = cx
.background_executor()
.spawn(async move { to_fenced_codeblock(&path, content) });
(buffer_info, text_task)
}

View File

@@ -36,6 +36,7 @@ pub struct ContextStrip {
}
impl ContextStrip {
#[allow(clippy::too_many_arguments)]
pub fn new(
context_store: Entity<ContextStore>,
workspace: WeakEntity<Workspace>,

View File

@@ -228,12 +228,8 @@ impl InlineAssistant {
return;
}
let Some(inline_assist_target) = Self::resolve_inline_assist_target(
workspace,
workspace.panel::<AssistantPanel>(cx),
window,
cx,
) else {
let Some(inline_assist_target) = Self::resolve_inline_assist_target(workspace, window, cx)
else {
return;
};
@@ -480,6 +476,7 @@ impl InlineAssistant {
}
}
#[allow(clippy::too_many_arguments)]
pub fn suggest_assist(
&mut self,
editor: &Entity<Editor>,
@@ -1387,7 +1384,6 @@ impl InlineAssistant {
fn resolve_inline_assist_target(
workspace: &mut Workspace,
assistant_panel: Option<Entity<AssistantPanel>>,
window: &mut Window,
cx: &mut App,
) -> Option<InlineAssistTarget> {
@@ -1407,20 +1403,7 @@ impl InlineAssistant {
}
}
let context_editor = assistant_panel
.and_then(|panel| panel.read(cx).active_context_editor())
.and_then(|editor| {
let editor = &editor.read(cx).editor().clone();
if editor.read(cx).is_focused(window) {
Some(editor.clone())
} else {
None
}
});
if let Some(context_editor) = context_editor {
Some(InlineAssistTarget::Editor(context_editor))
} else if let Some(workspace_editor) = workspace
if let Some(workspace_editor) = workspace
.active_item(cx)
.and_then(|item| item.act_as::<Editor>(cx))
{
@@ -1450,6 +1433,7 @@ struct InlineAssistScrollLock {
}
impl EditorInlineAssists {
#[allow(clippy::too_many_arguments)]
fn new(editor: &Entity<Editor>, window: &mut Window, cx: &mut App) -> Self {
let (highlight_updates_tx, mut highlight_updates_rx) = async_watch::channel(());
Self {
@@ -1561,6 +1545,7 @@ pub struct InlineAssist {
}
impl InlineAssist {
#[allow(clippy::too_many_arguments)]
fn new(
assist_id: InlineAssistId,
group_id: InlineAssistGroupId,

View File

@@ -823,6 +823,7 @@ impl InlineAssistId {
}
impl PromptEditor<BufferCodegen> {
#[allow(clippy::too_many_arguments)]
pub fn new_buffer(
id: InlineAssistId,
gutter_dimensions: Arc<Mutex<GutterDimensions>>,
@@ -983,6 +984,7 @@ impl TerminalInlineAssistId {
}
impl PromptEditor<TerminalCodegen> {
#[allow(clippy::too_many_arguments)]
pub fn new_terminal(
id: TerminalInlineAssistId,
prompt_history: VecDeque<String>,

View File

@@ -1,7 +1,7 @@
use crate::inline_prompt_editor::CodegenStatus;
use client::telemetry::Telemetry;
use futures::{channel::mpsc, SinkExt, StreamExt};
use gpui::{App, AppContext as _, Context, Entity, EventEmitter, Task};
use gpui::{App, Context, Entity, EventEmitter, Task};
use language_model::{LanguageModelRegistry, LanguageModelRequest};
use language_models::report_assistant_event;
use std::{sync::Arc, time::Instant};
@@ -53,7 +53,7 @@ impl TerminalCodegen {
let (mut hunks_tx, mut hunks_rx) = mpsc::channel(1);
let task = cx.background_spawn({
let task = cx.background_executor().spawn({
let message_id = message_id.clone();
let executor = cx.background_executor().clone();
async move {

View File

@@ -9,9 +9,7 @@ use context_server::manager::ContextServerManager;
use context_server::{ContextServerFactoryRegistry, ContextServerTool};
use futures::future::{self, BoxFuture, Shared};
use futures::FutureExt as _;
use gpui::{
prelude::*, App, BackgroundExecutor, Context, Entity, Global, ReadGlobal, SharedString, Task,
};
use gpui::{prelude::*, App, BackgroundExecutor, Context, Entity, SharedString, Task};
use heed::types::SerdeBincode;
use heed::Database;
use language_model::Role;
@@ -21,10 +19,6 @@ use util::ResultExt as _;
use crate::thread::{MessageId, Thread, ThreadId};
pub fn init(cx: &mut App) {
ThreadsDatabase::init(cx);
}
pub struct ThreadStore {
#[allow(unused)]
project: Entity<Project>,
@@ -32,6 +26,7 @@ pub struct ThreadStore {
context_server_manager: Entity<ContextServerManager>,
context_server_tool_ids: HashMap<Arc<str>, Vec<ToolId>>,
threads: Vec<SavedThreadMetadata>,
database_future: Shared<BoxFuture<'static, Result<Arc<ThreadsDatabase>, Arc<anyhow::Error>>>>,
}
impl ThreadStore {
@@ -46,12 +41,24 @@ impl ThreadStore {
ContextServerManager::new(context_server_factory_registry, project.clone(), cx)
});
let executor = cx.background_executor().clone();
let database_future = executor
.spawn({
let executor = executor.clone();
let database_path = paths::support_dir().join("threads/threads-db.0.mdb");
async move { ThreadsDatabase::new(database_path, executor) }
})
.then(|result| future::ready(result.map(Arc::new).map_err(Arc::new)))
.boxed()
.shared();
let this = Self {
project,
tools,
context_server_manager,
context_server_tool_ids: HashMap::default(),
threads: Vec::new(),
database_future,
};
this.register_context_server_handlers(cx);
this.reload(cx).detach_and_log_err(cx);
@@ -87,7 +94,7 @@ impl ThreadStore {
cx: &mut Context<Self>,
) -> Task<Result<Entity<Thread>>> {
let id = id.clone();
let database_future = ThreadsDatabase::global_future(cx);
let database_future = self.database_future.clone();
cx.spawn(|this, mut cx| async move {
let database = database_future.await.map_err(|err| anyhow!(err))?;
let thread = database
@@ -120,7 +127,7 @@ impl ThreadStore {
(id, thread)
});
let database_future = ThreadsDatabase::global_future(cx);
let database_future = self.database_future.clone();
cx.spawn(|this, mut cx| async move {
let database = database_future.await.map_err(|err| anyhow!(err))?;
database.save_thread(metadata, thread).await?;
@@ -131,7 +138,7 @@ impl ThreadStore {
pub fn delete_thread(&mut self, id: &ThreadId, cx: &mut Context<Self>) -> Task<Result<()>> {
let id = id.clone();
let database_future = ThreadsDatabase::global_future(cx);
let database_future = self.database_future.clone();
cx.spawn(|this, mut cx| async move {
let database = database_future.await.map_err(|err| anyhow!(err))?;
database.delete_thread(id.clone()).await?;
@@ -142,8 +149,8 @@ impl ThreadStore {
})
}
pub fn reload(&self, cx: &mut Context<Self>) -> Task<Result<()>> {
let database_future = ThreadsDatabase::global_future(cx);
fn reload(&self, cx: &mut Context<Self>) -> Task<Result<()>> {
let database_future = self.database_future.clone();
cx.spawn(|this, mut cx| async move {
let threads = database_future
.await
@@ -246,40 +253,13 @@ pub struct SavedMessage {
pub text: String,
}
struct GlobalThreadsDatabase(
Shared<BoxFuture<'static, Result<Arc<ThreadsDatabase>, Arc<anyhow::Error>>>>,
);
impl Global for GlobalThreadsDatabase {}
pub(crate) struct ThreadsDatabase {
struct ThreadsDatabase {
executor: BackgroundExecutor,
env: heed::Env,
threads: Database<SerdeBincode<ThreadId>, SerdeBincode<SavedThread>>,
}
impl ThreadsDatabase {
fn global_future(
cx: &mut App,
) -> Shared<BoxFuture<'static, Result<Arc<ThreadsDatabase>, Arc<anyhow::Error>>>> {
GlobalThreadsDatabase::global(cx).0.clone()
}
fn init(cx: &mut App) {
let executor = cx.background_executor().clone();
let database_future = executor
.spawn({
let executor = executor.clone();
let database_path = paths::support_dir().join("threads/threads-db.0.mdb");
async move { ThreadsDatabase::new(database_path, executor) }
})
.then(|result| future::ready(result.map(Arc::new).map_err(Arc::new)))
.boxed()
.shared();
cx.set_global(GlobalThreadsDatabase(database_future));
}
pub fn new(path: PathBuf, executor: BackgroundExecutor) -> Result<Self> {
std::fs::create_dir_all(&path)?;

View File

@@ -650,6 +650,7 @@ impl AssistantContext {
)
}
#[allow(clippy::too_many_arguments)]
pub fn new(
id: ContextId,
replica_id: ReplicaId,
@@ -770,6 +771,7 @@ impl AssistantContext {
}
}
#[allow(clippy::too_many_arguments)]
pub fn deserialize(
saved_context: SavedContext,
path: PathBuf,
@@ -849,7 +851,7 @@ impl AssistantContext {
.collect::<Vec<_>>();
context_ops.extend(self.pending_ops.iter().cloned());
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let buffer_ops = buffer_ops.await;
context_ops.sort_unstable_by_key(|op| op.timestamp());
buffer_ops
@@ -1190,14 +1192,11 @@ impl AssistantContext {
let Some(model) = LanguageModelRegistry::read_global(cx).active_model() else {
return;
};
let debounce = self.token_count.is_some();
self.pending_token_count = cx.spawn(|this, mut cx| {
async move {
if debounce {
cx.background_executor()
.timer(Duration::from_millis(200))
.await;
}
cx.background_executor()
.timer(Duration::from_millis(200))
.await;
let token_count = cx.update(|cx| model.count_tokens(request, cx))?.await?;
this.update(&mut cx, |this, cx| {

View File

@@ -193,8 +193,6 @@ pub struct ContextEditor {
// the file is opened. In order to keep the worktree alive for the duration of the
// context editor, we keep a reference here.
dragged_file_worktrees: Vec<Entity<Worktree>>,
language_model_selector: Entity<LanguageModelSelector>,
language_model_selector_menu_handle: PopoverMenuHandle<LanguageModelSelector>,
}
pub const DEFAULT_TAB_TITLE: &str = "New Chat";
@@ -240,22 +238,6 @@ impl ContextEditor {
cx.subscribe_in(&editor, window, Self::handle_editor_search_event),
];
let fs_clone = fs.clone();
let language_model_selector = cx.new(|cx| {
LanguageModelSelector::new(
move |model, cx| {
update_settings_file::<AssistantSettings>(
fs_clone.clone(),
cx,
move |settings, _| settings.set_model(model.clone()),
);
},
window,
cx,
)
});
let language_model_selector_menu_handle = PopoverMenuHandle::default();
let sections = context.read(cx).slash_command_output_sections().to_vec();
let patch_ranges = context.read(cx).patch_ranges().collect::<Vec<_>>();
let slash_commands = context.read(cx).slash_commands().clone();
@@ -280,8 +262,6 @@ impl ContextEditor {
show_accept_terms: false,
slash_menu_handle: Default::default(),
dragged_file_worktrees: Vec::new(),
language_model_selector,
language_model_selector_menu_handle,
};
this.update_message_headers(cx);
this.update_image_blocks(cx);
@@ -517,6 +497,7 @@ impl ContextEditor {
}
}
#[allow(clippy::too_many_arguments)]
pub fn run_command(
&mut self,
command_range: Range<language::Anchor>,
@@ -2057,6 +2038,7 @@ impl ContextEditor {
.unwrap_or_else(|| Cow::Borrowed(DEFAULT_TAB_TITLE))
}
#[allow(clippy::too_many_arguments)]
fn render_patch_block(
&mut self,
range: Range<text::Anchor>,
@@ -2373,61 +2355,15 @@ impl ContextEditor {
slash_command_picker::SlashCommandSelector::new(
self.slash_commands.clone(),
cx.entity().downgrade(),
IconButton::new("trigger", IconName::Plus)
Button::new("trigger", "Add Context")
.icon(IconName::Plus)
.icon_size(IconSize::Small)
.icon_color(Color::Muted),
move |window, cx| {
Tooltip::with_meta(
"Add Context",
None,
"Type / to insert via keyboard",
window,
cx,
)
},
.icon_color(Color::Muted)
.icon_position(IconPosition::Start),
Tooltip::text("Type / to insert via keyboard"),
)
}
fn render_language_model_selector(&self, cx: &mut Context<Self>) -> impl IntoElement {
let active_model = LanguageModelRegistry::read_global(cx).active_model();
let focus_handle = self.editor().focus_handle(cx).clone();
let model_name = match active_model {
Some(model) => model.name().0,
None => SharedString::from("No model selected"),
};
LanguageModelSelectorPopoverMenu::new(
self.language_model_selector.clone(),
ButtonLike::new("active-model")
.style(ButtonStyle::Subtle)
.child(
h_flex()
.gap_0p5()
.child(
Label::new(model_name)
.size(LabelSize::Small)
.color(Color::Muted),
)
.child(
Icon::new(IconName::ChevronDown)
.color(Color::Muted)
.size(IconSize::XSmall),
),
),
move |window, cx| {
Tooltip::for_action_in(
"Change Model",
&ToggleModelSelector,
&focus_handle,
window,
cx,
)
},
gpui::Corner::BottomLeft,
)
.with_handle(self.language_model_selector_menu_handle.clone())
}
fn render_last_error(&self, cx: &mut Context<Self>) -> Option<AnyElement> {
let last_error = self.last_error.as_ref()?;
@@ -2916,17 +2852,7 @@ impl Render for ContextEditor {
.border_t_1()
.border_color(cx.theme().colors().border_variant)
.bg(cx.theme().colors().editor_background)
.child(
h_flex()
.gap_1()
.child(self.render_inject_context_menu(cx))
.child(ui::Divider::vertical())
.child(
div()
.pl_0p5()
.child(self.render_language_model_selector(cx)),
),
)
.child(h_flex().gap_1().child(self.render_inject_context_menu(cx)))
.child(
h_flex()
.w_full()
@@ -3237,67 +3163,80 @@ impl FollowableItem for ContextEditor {
pub struct ContextEditorToolbarItem {
active_context_editor: Option<WeakEntity<ContextEditor>>,
model_summary_editor: Entity<Editor>,
language_model_selector: Entity<LanguageModelSelector>,
language_model_selector_menu_handle: PopoverMenuHandle<LanguageModelSelector>,
}
impl ContextEditorToolbarItem {
pub fn new(model_summary_editor: Entity<Editor>) -> Self {
pub fn new(
workspace: &Workspace,
model_selector_menu_handle: PopoverMenuHandle<LanguageModelSelector>,
model_summary_editor: Entity<Editor>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
Self {
active_context_editor: None,
model_summary_editor,
language_model_selector: cx.new(|cx| {
let fs = workspace.app_state().fs.clone();
LanguageModelSelector::new(
move |model, cx| {
update_settings_file::<AssistantSettings>(
fs.clone(),
cx,
move |settings, _| settings.set_model(model.clone()),
);
},
window,
cx,
)
}),
language_model_selector_menu_handle: model_selector_menu_handle,
}
}
}
pub fn render_remaining_tokens(
context_editor: &Entity<ContextEditor>,
cx: &App,
) -> Option<impl IntoElement> {
let context = &context_editor.read(cx).context;
let (token_count_color, token_count, max_token_count, tooltip) = match token_state(context, cx)?
{
TokenState::NoTokensLeft {
max_token_count,
token_count,
} => (
Color::Error,
token_count,
max_token_count,
Some("Token Limit Reached"),
),
TokenState::HasMoreTokens {
max_token_count,
token_count,
over_warn_threshold,
} => {
let (color, tooltip) = if over_warn_threshold {
(Color::Warning, Some("Token Limit is Close to Exhaustion"))
} else {
(Color::Muted, None)
};
(color, token_count, max_token_count, tooltip)
}
};
Some(
h_flex()
.id("token-count")
.gap_0p5()
.child(
Label::new(humanize_token_count(token_count))
.size(LabelSize::Small)
.color(token_count_color),
)
.child(Label::new("/").size(LabelSize::Small).color(Color::Muted))
.child(
Label::new(humanize_token_count(max_token_count))
.size(LabelSize::Small)
.color(Color::Muted),
)
.when_some(tooltip, |element, tooltip| {
element.tooltip(Tooltip::text(tooltip))
}),
)
fn render_remaining_tokens(&self, cx: &mut Context<Self>) -> Option<impl IntoElement> {
let context = &self
.active_context_editor
.as_ref()?
.upgrade()?
.read(cx)
.context;
let (token_count_color, token_count, max_token_count) = match token_state(context, cx)? {
TokenState::NoTokensLeft {
max_token_count,
token_count,
} => (Color::Error, token_count, max_token_count),
TokenState::HasMoreTokens {
max_token_count,
token_count,
over_warn_threshold,
} => {
let color = if over_warn_threshold {
Color::Warning
} else {
Color::Muted
};
(color, token_count, max_token_count)
}
};
Some(
h_flex()
.gap_0p5()
.child(
Label::new(humanize_token_count(token_count))
.size(LabelSize::Small)
.color(token_count_color),
)
.child(Label::new("/").size(LabelSize::Small).color(Color::Muted))
.child(
Label::new(humanize_token_count(max_token_count))
.size(LabelSize::Small)
.color(Color::Muted),
),
)
}
}
impl Render for ContextEditorToolbarItem {
@@ -3324,7 +3263,8 @@ impl Render for ContextEditorToolbarItem {
})),
),
);
let active_provider = LanguageModelRegistry::read_global(cx).active_provider();
let active_model = LanguageModelRegistry::read_global(cx).active_model();
let right_side = h_flex()
.gap_2()
// TODO display this in a nicer way, once we have a design for it.
@@ -3340,12 +3280,57 @@ impl Render for ContextEditorToolbarItem {
// scan_items_remaining
// .map(|remaining_items| format!("Files to scan: {}", remaining_items))
// })
.children(
self.active_context_editor
.as_ref()
.and_then(|editor| editor.upgrade())
.and_then(|editor| render_remaining_tokens(&editor, cx)),
);
.child(
LanguageModelSelectorPopoverMenu::new(
self.language_model_selector.clone(),
ButtonLike::new("active-model")
.style(ButtonStyle::Subtle)
.child(
h_flex()
.w_full()
.gap_0p5()
.child(
div()
.overflow_x_hidden()
.flex_grow()
.whitespace_nowrap()
.child(match (active_provider, active_model) {
(Some(provider), Some(model)) => h_flex()
.gap_1()
.child(
Icon::new(
model
.icon()
.unwrap_or_else(|| provider.icon()),
)
.color(Color::Muted)
.size(IconSize::XSmall),
)
.child(
Label::new(model.name().0)
.size(LabelSize::Small)
.color(Color::Muted),
)
.into_any_element(),
_ => Label::new("No model selected")
.size(LabelSize::Small)
.color(Color::Muted)
.into_any_element(),
}),
)
.child(
Icon::new(IconName::ChevronDown)
.color(Color::Muted)
.size(IconSize::XSmall),
),
),
move |window, cx| {
Tooltip::for_action("Change Model", &ToggleModelSelector, window, cx)
},
)
.with_handle(self.language_model_selector_menu_handle.clone()),
)
.children(self.render_remaining_tokens(cx));
h_flex()
.px_0p5()

View File

@@ -265,18 +265,19 @@ impl ContextStore {
local_versions.push(context.version(cx).to_proto(context_id.clone()));
let client = this.client.clone();
let project_id = envelope.payload.project_id;
cx.background_spawn(async move {
let operations = operations.await;
for operation in operations {
client.send(proto::UpdateContext {
project_id,
context_id: context_id.to_proto(),
operation: Some(operation),
})?;
}
anyhow::Ok(())
})
.detach_and_log_err(cx);
cx.background_executor()
.spawn(async move {
let operations = operations.await;
for operation in operations {
client.send(proto::UpdateContext {
project_id,
context_id: context_id.to_proto(),
operation: Some(operation),
})?;
}
anyhow::Ok(())
})
.detach_and_log_err(cx);
}
}
@@ -400,7 +401,8 @@ impl ContextStore {
)
})?;
let operations = cx
.background_spawn(async move {
.background_executor()
.spawn(async move {
context_proto
.operations
.into_iter()
@@ -434,7 +436,7 @@ impl ContextStore {
let languages = self.languages.clone();
let project = self.project.clone();
let telemetry = self.telemetry.clone();
let load = cx.background_spawn({
let load = cx.background_executor().spawn({
let path = path.clone();
async move {
let saved_context = fs.load(&path).await?;
@@ -537,7 +539,8 @@ impl ContextStore {
)
})?;
let operations = cx
.background_spawn(async move {
.background_executor()
.spawn(async move {
context_proto
.operations
.into_iter()
@@ -690,7 +693,7 @@ impl ContextStore {
pub fn search(&self, query: String, cx: &App) -> Task<Vec<SavedContextMetadata>> {
let metadata = self.contexts_metadata.clone();
let executor = cx.background_executor().clone();
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
if query.is_empty() {
metadata
} else {

View File

@@ -2,7 +2,7 @@ use anyhow::{anyhow, Context as _, Result};
use collections::HashMap;
use editor::ProposedChangesEditor;
use futures::{future, TryFutureExt as _};
use gpui::{App, AppContext as _, AsyncApp, Entity, SharedString};
use gpui::{App, AsyncApp, Entity, SharedString};
use language::{AutoindentMode, Buffer, BufferSnapshot};
use project::{Project, ProjectPath};
use std::{cmp, ops::Range, path::Path, sync::Arc};
@@ -258,7 +258,8 @@ impl AssistantEdit {
let snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot())?;
let suggestion = cx
.background_spawn(async move { kind.resolve(&snapshot) })
.background_executor()
.spawn(async move { kind.resolve(&snapshot) })
.await;
Ok((buffer, suggestion))
@@ -546,7 +547,7 @@ impl Eq for AssistantPatch {}
#[cfg(test)]
mod tests {
use super::*;
use gpui::App;
use gpui::{App, AppContext as _};
use language::{
language_settings::AllLanguageSettings, Language, LanguageConfig, LanguageMatcher,
};

View File

@@ -4,10 +4,10 @@ pub use assistant_slash_command::SlashCommand;
use assistant_slash_command::{AfterCompletion, SlashCommandLine, SlashCommandWorkingSet};
use editor::{CompletionProvider, Editor};
use fuzzy::{match_strings, StringMatchCandidate};
use gpui::{App, AppContext as _, Context, Entity, Task, WeakEntity, Window};
use language::{Anchor, Buffer, LanguageServerId, ToPoint};
use gpui::{App, Context, Entity, Task, WeakEntity, Window};
use language::{Anchor, Buffer, CompletionDocumentation, LanguageServerId, ToPoint};
use parking_lot::Mutex;
use project::{lsp_store::CompletionDocumentation, CompletionIntent};
use project::CompletionIntent;
use rope::Point;
use std::{
cell::RefCell,
@@ -121,7 +121,7 @@ impl SlashCommandCompletionProvider {
Some(project::Completion {
old_range: name_range.clone(),
documentation: Some(CompletionDocumentation::SingleLine(
command.description().into(),
command.description(),
)),
new_text,
label: command.label(cx),
@@ -136,6 +136,7 @@ impl SlashCommandCompletionProvider {
})
}
#[allow(clippy::too_many_arguments)]
fn complete_command_argument(
&self,
command_name: &str,
@@ -162,7 +163,7 @@ impl SlashCommandCompletionProvider {
let editor = self.editor.clone();
let workspace = self.workspace.clone();
let arguments = arguments.to_vec();
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
Ok(completions
.await?
.into_iter()

View File

@@ -102,7 +102,8 @@ impl PickerDelegate for SlashCommandDelegate {
let all_commands = self.all_commands.clone();
cx.spawn_in(window, |this, mut cx| async move {
let filtered_commands = cx
.background_spawn(async move {
.background_executor()
.spawn(async move {
if query.is_empty() {
all_commands
} else {

View File

@@ -88,7 +88,7 @@ pub trait SlashCommand: 'static + Send + Sync {
fn accepts_arguments(&self) -> bool {
self.requires_argument()
}
#[allow(clippy::too_many_arguments)]
fn run(
self: Arc<Self>,
arguments: &[String],

View File

@@ -103,7 +103,7 @@ impl SlashCommand for ExtensionSlashCommand {
) -> Task<Result<Vec<ArgumentCompletion>>> {
let command = self.command.clone();
let arguments = arguments.to_owned();
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let completions = self
.extension
.complete_slash_command_argument(command, arguments)
@@ -135,7 +135,7 @@ impl SlashCommand for ExtensionSlashCommand {
) -> Task<SlashCommandResult> {
let command = self.command.clone();
let arguments = arguments.to_owned();
let output = cx.background_spawn(async move {
let output = cx.background_executor().spawn(async move {
let delegate =
delegate.map(|delegate| Arc::new(WorktreeDelegateAdapter(delegate.clone())) as _);
let output = self

View File

@@ -82,7 +82,7 @@ impl SlashCommand for AutoCommand {
project_index.flush_summary_backlogs(cx)
})?;
cx.background_spawn(task).await;
cx.background_executor().spawn(task).await;
anyhow::Ok(Vec::new())
})
@@ -129,7 +129,7 @@ impl SlashCommand for AutoCommand {
// so you don't have to write it again.
let original_prompt = argument.to_string();
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let commands = task.await?;
let mut prompt = String::new();
@@ -285,56 +285,57 @@ async fn commands_for_summaries(
})
.collect::<Vec<_>>();
cx.background_spawn(async move {
let futures = completion_streams
.into_iter()
.enumerate()
.map(|(ix, (stream, tx))| async move {
let start = std::time::Instant::now();
let events = stream.await?;
log::info!("Time taken for awaiting /await chunk stream #{ix}: {:?}", start.elapsed());
cx.background_executor()
.spawn(async move {
let futures = completion_streams
.into_iter()
.enumerate()
.map(|(ix, (stream, tx))| async move {
let start = std::time::Instant::now();
let events = stream.await?;
log::info!("Time taken for awaiting /await chunk stream #{ix}: {:?}", start.elapsed());
let completion: String = events
.filter_map(|event| async {
if let Ok(LanguageModelCompletionEvent::Text(text)) = event {
Some(text)
} else {
None
}
})
.collect()
.await;
log::info!("Time taken for all /auto chunks to come back for #{ix}: {:?}", start.elapsed());
for line in completion.split('\n') {
if let Some(first_space) = line.find(' ') {
let command = &line[..first_space].trim();
let arg = &line[first_space..].trim();
tx.send(CommandToRun {
name: command.to_string(),
arg: arg.to_string(),
let completion: String = events
.filter_map(|event| async {
if let Ok(LanguageModelCompletionEvent::Text(text)) = event {
Some(text)
} else {
None
}
})
.await?;
} else if !line.trim().is_empty() {
// All slash-commands currently supported in context inference need a space for the argument.
log::warn!(
"Context inference returned a non-blank line that contained no spaces (meaning no argument for the slash command): {:?}",
line
);
.collect()
.await;
log::info!("Time taken for all /auto chunks to come back for #{ix}: {:?}", start.elapsed());
for line in completion.split('\n') {
if let Some(first_space) = line.find(' ') {
let command = &line[..first_space].trim();
let arg = &line[first_space..].trim();
tx.send(CommandToRun {
name: command.to_string(),
arg: arg.to_string(),
})
.await?;
} else if !line.trim().is_empty() {
// All slash-commands currently supported in context inference need a space for the argument.
log::warn!(
"Context inference returned a non-blank line that contained no spaces (meaning no argument for the slash command): {:?}",
line
);
}
}
}
anyhow::Ok(())
})
.collect::<Vec<_>>();
anyhow::Ok(())
})
.collect::<Vec<_>>();
let _ = futures::future::try_join_all(futures).await.log_err();
let _ = futures::future::try_join_all(futures).await.log_err();
let duration = all_start.elapsed();
eprintln!("All futures completed in {:?}", duration);
})
let duration = all_start.elapsed();
eprintln!("All futures completed in {:?}", duration);
})
.await;
drop(tx); // Close the channel so that rx.collect() won't hang. This is safe because all futures have completed.

View File

@@ -132,7 +132,7 @@ impl SlashCommand for CargoWorkspaceSlashCommand {
let project = workspace.project().clone();
let fs = workspace.project().read(cx).fs().clone();
let path = Self::path_to_cargo_toml(project, cx);
let output = cx.background_spawn(async move {
let output = cx.background_executor().spawn(async move {
let path = path.with_context(|| "Cargo.toml not found")?;
Self::build_message(fs, &path).await
});

View File

@@ -54,7 +54,7 @@ impl SlashCommand for DefaultSlashCommand {
cx: &mut App,
) -> Task<SlashCommandResult> {
let store = PromptStore::global(cx);
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let store = store.await?;
let prompts = store.default_prompt_metadata();

View File

@@ -86,7 +86,7 @@ impl SlashCommand for DeltaSlashCommand {
}
}
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let mut output = SlashCommandOutput::default();
let mut changes_detected = false;

View File

@@ -129,7 +129,7 @@ impl SlashCommand for DiagnosticsSlashCommand {
let paths = self.search_paths(query.clone(), cancellation_flag.clone(), &workspace, cx);
let executor = cx.background_executor().clone();
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let mut matches: Vec<String> = paths
.await
.into_iter()

View File

@@ -176,7 +176,7 @@ impl SlashCommand for DocsSlashCommand {
.provider()
.ok_or_else(|| anyhow!("no docs provider specified"))
.and_then(|provider| IndexedDocsStore::try_global(provider, cx));
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
fn build_completions(items: Vec<String>) -> Vec<ArgumentCompletion> {
items
.into_iter()
@@ -284,7 +284,7 @@ impl SlashCommand for DocsSlashCommand {
let args = DocsSlashCommandArgs::parse(arguments);
let executor = cx.background_executor().clone();
let task = cx.background_spawn({
let task = cx.background_executor().spawn({
let store = args
.provider()
.ok_or_else(|| anyhow!("no docs provider specified"))

View File

@@ -151,7 +151,7 @@ impl SlashCommand for FetchSlashCommand {
let http_client = workspace.read(cx).client().http_client();
let url = argument.to_string();
let text = cx.background_spawn({
let text = cx.background_executor().spawn({
let url = url.clone();
async move { Self::build_message(http_client, &url).await }
});

View File

@@ -156,7 +156,7 @@ impl SlashCommand for FileSlashCommand {
cx,
);
let comment_id = cx.theme().syntax().highlight_id("comment").map(HighlightId);
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
Ok(paths
.await
.into_iter()

View File

@@ -130,48 +130,49 @@ impl SlashCommand for ProjectSlashCommand {
let results = SemanticDb::load_results(results, &fs, &cx).await?;
cx.background_spawn(async move {
let mut output = "Project context:\n".to_string();
let mut sections = Vec::new();
cx.background_executor()
.spawn(async move {
let mut output = "Project context:\n".to_string();
let mut sections = Vec::new();
for (ix, query) in search_queries.into_iter().enumerate() {
let start_ix = output.len();
writeln!(&mut output, "Results for {query}:").unwrap();
let mut has_results = false;
for result in &results {
if result.query_index == ix {
add_search_result_section(result, &mut output, &mut sections);
has_results = true;
for (ix, query) in search_queries.into_iter().enumerate() {
let start_ix = output.len();
writeln!(&mut output, "Results for {query}:").unwrap();
let mut has_results = false;
for result in &results {
if result.query_index == ix {
add_search_result_section(result, &mut output, &mut sections);
has_results = true;
}
}
if has_results {
sections.push(SlashCommandOutputSection {
range: start_ix..output.len(),
icon: IconName::MagnifyingGlass,
label: query.into(),
metadata: None,
});
output.push('\n');
} else {
output.truncate(start_ix);
}
}
if has_results {
sections.push(SlashCommandOutputSection {
range: start_ix..output.len(),
icon: IconName::MagnifyingGlass,
label: query.into(),
metadata: None,
});
output.push('\n');
} else {
output.truncate(start_ix);
sections.push(SlashCommandOutputSection {
range: 0..output.len(),
icon: IconName::Book,
label: "Project context".into(),
metadata: None,
});
Ok(SlashCommandOutput {
text: output,
sections,
run_commands_in_text: true,
}
}
sections.push(SlashCommandOutputSection {
range: 0..output.len(),
icon: IconName::Book,
label: "Project context".into(),
metadata: None,
});
Ok(SlashCommandOutput {
text: output,
sections,
run_commands_in_text: true,
}
.to_event_stream())
})
.await
.to_event_stream())
})
.await
})
}
}

View File

@@ -43,7 +43,7 @@ impl SlashCommand for PromptSlashCommand {
) -> Task<Result<Vec<ArgumentCompletion>>> {
let store = PromptStore::global(cx);
let query = arguments.to_owned().join(" ");
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let prompts = store.await?.search(query).await;
Ok(prompts
.into_iter()
@@ -77,7 +77,7 @@ impl SlashCommand for PromptSlashCommand {
let store = PromptStore::global(cx);
let title = SharedString::from(title.clone());
let prompt = cx.background_spawn({
let prompt = cx.background_executor().spawn({
let title = title.clone();
async move {
let store = store.await?;

View File

@@ -119,7 +119,8 @@ impl SlashCommand for SearchSlashCommand {
let loaded_results = SemanticDb::load_results(results, &fs, &cx).await?;
let output = cx
.background_spawn(async move {
.background_executor()
.spawn(async move {
let mut text = format!("Search results for {query}:\n");
let mut sections = Vec::new();
for loaded_result in &loaded_results {

View File

@@ -63,55 +63,56 @@ impl SlashCommand for StreamingExampleSlashCommand {
cx: &mut App,
) -> Task<SlashCommandResult> {
let (events_tx, events_rx) = mpsc::unbounded();
cx.background_spawn(async move {
events_tx.unbounded_send(Ok(SlashCommandEvent::StartSection {
icon: IconName::FileRust,
label: "Section 1".into(),
metadata: None,
}))?;
events_tx.unbounded_send(Ok(SlashCommandEvent::Content(
SlashCommandContent::Text {
text: "Hello".into(),
run_commands_in_text: false,
},
)))?;
events_tx.unbounded_send(Ok(SlashCommandEvent::EndSection))?;
Timer::after(Duration::from_secs(1)).await;
events_tx.unbounded_send(Ok(SlashCommandEvent::StartSection {
icon: IconName::FileRust,
label: "Section 2".into(),
metadata: None,
}))?;
events_tx.unbounded_send(Ok(SlashCommandEvent::Content(
SlashCommandContent::Text {
text: "World".into(),
run_commands_in_text: false,
},
)))?;
events_tx.unbounded_send(Ok(SlashCommandEvent::EndSection))?;
for n in 1..=10 {
Timer::after(Duration::from_secs(1)).await;
cx.background_executor()
.spawn(async move {
events_tx.unbounded_send(Ok(SlashCommandEvent::StartSection {
icon: IconName::StarFilled,
label: format!("Section {n}").into(),
icon: IconName::FileRust,
label: "Section 1".into(),
metadata: None,
}))?;
events_tx.unbounded_send(Ok(SlashCommandEvent::Content(
SlashCommandContent::Text {
text: "lorem ipsum ".repeat(n).trim().into(),
text: "Hello".into(),
run_commands_in_text: false,
},
)))?;
events_tx.unbounded_send(Ok(SlashCommandEvent::EndSection))?;
}
anyhow::Ok(())
})
.detach_and_log_err(cx);
Timer::after(Duration::from_secs(1)).await;
events_tx.unbounded_send(Ok(SlashCommandEvent::StartSection {
icon: IconName::FileRust,
label: "Section 2".into(),
metadata: None,
}))?;
events_tx.unbounded_send(Ok(SlashCommandEvent::Content(
SlashCommandContent::Text {
text: "World".into(),
run_commands_in_text: false,
},
)))?;
events_tx.unbounded_send(Ok(SlashCommandEvent::EndSection))?;
for n in 1..=10 {
Timer::after(Duration::from_secs(1)).await;
events_tx.unbounded_send(Ok(SlashCommandEvent::StartSection {
icon: IconName::StarFilled,
label: format!("Section {n}").into(),
metadata: None,
}))?;
events_tx.unbounded_send(Ok(SlashCommandEvent::Content(
SlashCommandContent::Text {
text: "lorem ipsum ".repeat(n).trim().into(),
run_commands_in_text: false,
},
)))?;
events_tx.unbounded_send(Ok(SlashCommandEvent::EndSection))?;
}
anyhow::Ok(())
})
.detach_and_log_err(cx);
Task::ready(Ok(events_rx.boxed()))
}

View File

@@ -4,7 +4,7 @@ use assistant_slash_command::{
SlashCommandResult,
};
use editor::Editor;
use gpui::{AppContext as _, Task, WeakEntity};
use gpui::{Task, WeakEntity};
use language::{BufferSnapshot, LspAdapterDelegate};
use std::sync::Arc;
use std::{path::Path, sync::atomic::AtomicBool};
@@ -69,7 +69,7 @@ impl SlashCommand for OutlineSlashCommand {
let snapshot = buffer.read(cx).snapshot();
let path = snapshot.resolve_file_path(cx, true);
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let outline = snapshot
.outline(None)
.context("no symbols for active tab")?;

View File

@@ -152,7 +152,7 @@ impl SlashCommand for TabSlashCommand {
cx,
);
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let mut output = SlashCommandOutput::default();
for (full_path, buffer, _) in tab_items_search.await? {
append_buffer_to_output(&buffer, full_path.as_deref(), &mut output).log_err();
@@ -212,73 +212,74 @@ fn tab_items_for_queries(
})??;
let background_executor = cx.background_executor().clone();
cx.background_spawn(async move {
open_buffers.sort_by_key(|(_, _, timestamp)| *timestamp);
if empty_query
|| queries
.iter()
.any(|query| query == ALL_TABS_COMPLETION_ITEM)
{
return Ok(open_buffers);
}
cx.background_executor()
.spawn(async move {
open_buffers.sort_by_key(|(_, _, timestamp)| *timestamp);
if empty_query
|| queries
.iter()
.any(|query| query == ALL_TABS_COMPLETION_ITEM)
{
return Ok(open_buffers);
}
let matched_items = if strict_match {
let match_candidates = open_buffers
.iter()
.enumerate()
.filter_map(|(id, (full_path, ..))| {
let path_string = full_path.as_deref()?.to_string_lossy().to_string();
Some((id, path_string))
})
.fold(HashMap::default(), |mut candidates, (id, path_string)| {
candidates
.entry(path_string)
.or_insert_with(Vec::new)
.push(id);
candidates
let matched_items = if strict_match {
let match_candidates = open_buffers
.iter()
.enumerate()
.filter_map(|(id, (full_path, ..))| {
let path_string = full_path.as_deref()?.to_string_lossy().to_string();
Some((id, path_string))
})
.fold(HashMap::default(), |mut candidates, (id, path_string)| {
candidates
.entry(path_string)
.or_insert_with(Vec::new)
.push(id);
candidates
});
queries
.iter()
.filter_map(|query| match_candidates.get(query))
.flatten()
.copied()
.filter_map(|id| open_buffers.get(id))
.cloned()
.collect()
} else {
let match_candidates = open_buffers
.iter()
.enumerate()
.filter_map(|(id, (full_path, ..))| {
let path_string = full_path.as_deref()?.to_string_lossy().to_string();
Some(fuzzy::StringMatchCandidate::new(id, &path_string))
})
.collect::<Vec<_>>();
let mut processed_matches = HashSet::default();
let file_queries = queries.iter().map(|query| {
fuzzy::match_strings(
&match_candidates,
query,
true,
usize::MAX,
&cancel,
background_executor.clone(),
)
});
queries
.iter()
.filter_map(|query| match_candidates.get(query))
.flatten()
.copied()
.filter_map(|id| open_buffers.get(id))
.cloned()
.collect()
} else {
let match_candidates = open_buffers
.iter()
.enumerate()
.filter_map(|(id, (full_path, ..))| {
let path_string = full_path.as_deref()?.to_string_lossy().to_string();
Some(fuzzy::StringMatchCandidate::new(id, &path_string))
})
.collect::<Vec<_>>();
let mut processed_matches = HashSet::default();
let file_queries = queries.iter().map(|query| {
fuzzy::match_strings(
&match_candidates,
query,
true,
usize::MAX,
&cancel,
background_executor.clone(),
)
});
join_all(file_queries)
.await
.into_iter()
.flatten()
.filter(|string_match| processed_matches.insert(string_match.candidate_id))
.filter_map(|string_match| open_buffers.get(string_match.candidate_id))
.cloned()
.collect()
};
Ok(matched_items)
})
.await
join_all(file_queries)
.await
.into_iter()
.flatten()
.filter(|string_match| processed_matches.insert(string_match.candidate_id))
.filter_map(|string_match| open_buffers.get(string_match.candidate_id))
.cloned()
.collect()
};
Ok(matched_items)
})
.await
})
}

View File

@@ -513,7 +513,7 @@ impl AutoUpdater {
should_show: bool,
cx: &App,
) -> Task<Result<()>> {
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
if should_show {
KEY_VALUE_STORE
.write_kvp(
@@ -531,7 +531,7 @@ impl AutoUpdater {
}
pub fn should_show_update_notification(&self, cx: &App) -> Task<Result<bool>> {
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
Ok(KEY_VALUE_STORE
.read_kvp(SHOULD_SHOW_UPDATE_NOTIFICATION_KEY)?
.is_some())

View File

@@ -19,6 +19,7 @@ editor.workspace = true
gpui.workspace = true
http_client.workspace = true
markdown_preview.workspace = true
menu.workspace = true
release_channel.workspace = true
serde.workspace = true
serde_json.workspace = true

View File

@@ -1,17 +1,19 @@
mod update_notification;
use auto_update::AutoUpdater;
use client::proto::UpdateNotification;
use editor::{Editor, MultiBuffer};
use gpui::{actions, prelude::*, App, Context, DismissEvent, Entity, SharedString, Window};
use gpui::{actions, prelude::*, App, Context, Entity, SharedString, Window};
use http_client::HttpClient;
use markdown_preview::markdown_preview_view::{MarkdownPreviewMode, MarkdownPreviewView};
use release_channel::{AppVersion, ReleaseChannel};
use serde::Deserialize;
use smol::io::AsyncReadExt;
use util::ResultExt as _;
use workspace::notifications::simple_message_notification::MessageNotification;
use workspace::notifications::{show_app_notification, NotificationId};
use workspace::Workspace;
use crate::update_notification::UpdateNotification;
actions!(auto_update, [ViewReleaseNotesLocally]);
pub fn init(cx: &mut App) {
@@ -129,32 +131,19 @@ pub fn notify_if_app_was_updated(cx: &mut App) {
let Some(updater) = AutoUpdater::get(cx) else {
return;
};
let version = updater.read(cx).current_version();
let should_show_notification = updater.read(cx).should_show_update_notification(cx);
cx.spawn(|cx| async move {
let should_show_notification = should_show_notification.await?;
if should_show_notification {
cx.update(|cx| {
let version = updater.read(cx).current_version();
let app_name = ReleaseChannel::global(cx).display_name();
show_app_notification(
NotificationId::unique::<UpdateNotification>(),
cx,
move |cx| {
let workspace_handle = cx.entity().downgrade();
cx.new(|_cx| {
MessageNotification::new(format!("Updated to {app_name} {}", version))
.primary_message("View Release Notes")
.primary_on_click(move |window, cx| {
if let Some(workspace) = workspace_handle.upgrade() {
workspace.update(cx, |workspace, cx| {
crate::view_release_notes_locally(
workspace, window, cx,
);
})
}
cx.emit(DismissEvent);
})
})
cx.new(|_| UpdateNotification::new(version, workspace_handle))
},
);
updater.update(cx, |updater, cx| {

View File

@@ -0,0 +1,70 @@
use gpui::{
div, Context, DismissEvent, EventEmitter, InteractiveElement, IntoElement, ParentElement,
Render, SemanticVersion, StatefulInteractiveElement, Styled, WeakEntity, Window,
};
use menu::Cancel;
use release_channel::ReleaseChannel;
use util::ResultExt;
use workspace::{
ui::{h_flex, v_flex, Icon, IconName, Label, StyledExt},
Workspace,
};
pub struct UpdateNotification {
version: SemanticVersion,
workspace: WeakEntity<Workspace>,
}
impl EventEmitter<DismissEvent> for UpdateNotification {}
impl Render for UpdateNotification {
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let app_name = ReleaseChannel::global(cx).display_name();
v_flex()
.on_action(cx.listener(UpdateNotification::dismiss))
.elevation_3(cx)
.p_4()
.child(
h_flex()
.justify_between()
.child(Label::new(format!(
"Updated to {app_name} {}",
self.version
)))
.child(
div()
.id("cancel")
.child(Icon::new(IconName::Close))
.cursor_pointer()
.on_click(cx.listener(|this, _, window, cx| {
this.dismiss(&menu::Cancel, window, cx)
})),
),
)
.child(
div()
.id("notes")
.child(Label::new("View the release notes"))
.cursor_pointer()
.on_click(cx.listener(|this, _, window, cx| {
this.workspace
.update(cx, |workspace, cx| {
crate::view_release_notes_locally(workspace, window, cx);
})
.log_err();
this.dismiss(&menu::Cancel, window, cx)
})),
)
}
}
impl UpdateNotification {
pub fn new(version: SemanticVersion, workspace: WeakEntity<Workspace>) -> Self {
Self { version, workspace }
}
pub fn dismiss(&mut self, _: &Cancel, _: &mut Window, cx: &mut Context<Self>) {
cx.emit(DismissEvent);
}
}

View File

@@ -1,6 +1,6 @@
use futures::{channel::oneshot, future::OptionFuture};
use git2::{DiffLineType as GitDiffLineType, DiffOptions as GitOptions, Patch as GitPatch};
use gpui::{App, AppContext as _, AsyncApp, Context, Entity, EventEmitter};
use gpui::{App, AsyncApp, Context, Entity, EventEmitter};
use language::{Language, LanguageRegistry};
use rope::Rope;
use std::{cmp, future::Future, iter, ops::Range, sync::Arc};
@@ -615,9 +615,11 @@ impl BufferDiff {
cx,
)
});
let base_text_snapshot = cx.background_spawn(OptionFuture::from(base_text_snapshot));
let base_text_snapshot = cx
.background_executor()
.spawn(OptionFuture::from(base_text_snapshot));
let hunks = cx.background_spawn({
let hunks = cx.background_executor().spawn({
let buffer = buffer.clone();
async move { compute_hunks(diff_base, buffer) }
});
@@ -639,7 +641,7 @@ impl BufferDiff {
.clone()
.map(|buffer| buffer.as_rope().clone()),
);
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
BufferDiffInner {
hunks: compute_hunks(diff_base, buffer),
base_text: diff_base_buffer,
@@ -719,6 +721,7 @@ impl BufferDiff {
Some(start..end)
}
#[allow(clippy::too_many_arguments)]
pub async fn update_diff(
this: Entity<BufferDiff>,
buffer: text::BufferSnapshot,
@@ -996,7 +999,7 @@ mod tests {
use std::fmt::Write as _;
use super::*;
use gpui::TestAppContext;
use gpui::{AppContext as _, TestAppContext};
use rand::{rngs::StdRng, Rng as _};
use text::{Buffer, BufferId, Rope};
use unindent::Unindent as _;

View File

@@ -241,7 +241,7 @@ impl ActiveCall {
})
.shared();
self.pending_room_creation = Some(room.clone());
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
room.await.map_err(|err| anyhow!("{:?}", err))?;
anyhow::Ok(())
})
@@ -278,7 +278,7 @@ impl ActiveCall {
};
let client = self.client.clone();
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
client
.request(proto::CancelCall {
room_id,

View File

@@ -13,7 +13,7 @@ use client::{
use collections::{BTreeMap, HashMap, HashSet};
use fs::Fs;
use futures::{FutureExt, StreamExt};
use gpui::{App, AppContext as _, AsyncApp, Context, Entity, EventEmitter, Task, WeakEntity};
use gpui::{App, AppContext, AsyncApp, Context, Entity, EventEmitter, Task, WeakEntity};
use language::LanguageRegistry;
#[cfg(not(all(target_os = "windows", target_env = "gnu")))]
use livekit::{
@@ -255,7 +255,7 @@ impl Room {
fn app_will_quit(&mut self, cx: &mut Context<Self>) -> impl Future<Output = ()> {
let task = if self.status.is_online() {
let leave = self.leave_internal(cx);
Some(cx.background_spawn(async move {
Some(cx.background_executor().spawn(async move {
leave.await.log_err();
}))
} else {
@@ -322,7 +322,7 @@ impl Room {
self.clear_state(cx);
let leave_room = self.client.request(proto::LeaveRoom {});
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
leave_room.await?;
anyhow::Ok(())
})
@@ -1248,7 +1248,7 @@ impl Room {
};
cx.notify();
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
client
.request(proto::UpdateParticipantLocation {
room_id,
@@ -1373,10 +1373,11 @@ impl Room {
match publication {
Ok(publication) => {
if canceled {
cx.background_spawn(async move {
participant.unpublish_track(&publication.sid()).await
})
.detach_and_log_err(cx)
cx.background_executor()
.spawn(async move {
participant.unpublish_track(&publication.sid()).await
})
.detach_and_log_err(cx)
} else {
if live_kit.muted_by_user || live_kit.deafened {
publication.mute();
@@ -1464,10 +1465,11 @@ impl Room {
match publication {
Ok(publication) => {
if canceled {
cx.background_spawn(async move {
participant.unpublish_track(&publication.sid()).await
})
.detach()
cx.background_executor()
.spawn(async move {
participant.unpublish_track(&publication.sid()).await
})
.detach()
} else {
live_kit.screen_track = LocalTrack::Published {
track_publication: publication,
@@ -1559,10 +1561,9 @@ impl Room {
{
let local_participant = live_kit.room.local_participant();
let sid = track_publication.sid();
cx.background_spawn(
async move { local_participant.unpublish_track(&sid).await },
)
.detach_and_log_err(cx);
cx.background_executor()
.spawn(async move { local_participant.unpublish_track(&sid).await })
.detach_and_log_err(cx);
cx.notify();
}
@@ -1721,12 +1722,13 @@ impl LiveKitRoom {
}
let participant = self.room.local_participant();
cx.background_spawn(async move {
for sid in tracks_to_unpublish {
participant.unpublish_track(&sid).await.log_err();
}
})
.detach();
cx.background_executor()
.spawn(async move {
for sid in tracks_to_unpublish {
participant.unpublish_track(&sid).await.log_err();
}
})
.detach();
}
}

View File

@@ -234,7 +234,7 @@ impl ActiveCall {
})
.shared();
self.pending_room_creation = Some(room.clone());
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
room.await.map_err(|err| anyhow!("{:?}", err))?;
anyhow::Ok(())
})
@@ -271,7 +271,7 @@ impl ActiveCall {
};
let client = self.client.clone();
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
client
.request(proto::CancelCall {
room_id,

View File

@@ -311,7 +311,7 @@ impl Room {
fn app_will_quit(&mut self, cx: &mut Context<Self>) -> impl Future<Output = ()> {
let task = if self.status.is_online() {
let leave = self.leave_internal(cx);
Some(cx.background_spawn(async move {
Some(cx.background_executor().spawn(async move {
leave.await.log_err();
}))
} else {
@@ -378,7 +378,7 @@ impl Room {
self.clear_state(cx);
let leave_room = self.client.request(proto::LeaveRoom {});
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
leave_room.await?;
anyhow::Ok(())
})
@@ -1268,7 +1268,7 @@ impl Room {
};
cx.notify();
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
client
.request(proto::UpdateParticipantLocation {
room_id,
@@ -1385,7 +1385,9 @@ impl Room {
live_kit.room.unpublish_track(publication);
} else {
if live_kit.muted_by_user || live_kit.deafened {
cx.background_spawn(publication.set_mute(true)).detach();
cx.background_executor()
.spawn(publication.set_mute(true))
.detach();
}
live_kit.microphone_track = LocalTrack::Published {
track_publication: publication,

View File

@@ -514,7 +514,8 @@ impl ChannelStore {
}
}
};
cx.background_spawn(async move { task.await.map_err(|error| anyhow!("{}", error)) })
cx.background_executor()
.spawn(async move { task.await.map_err(|error| anyhow!("{}", error)) })
}
pub fn is_channel_admin(&self, channel_id: ChannelId) -> bool {
@@ -780,7 +781,7 @@ impl ChannelStore {
cx: &mut Context<Self>,
) -> Task<Result<()>> {
let client = self.client.clone();
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
client
.request(proto::RespondToChannelInvite {
channel_id: channel_id.0,
@@ -974,18 +975,21 @@ impl ChannelStore {
if let Some(operations) = operations {
let client = this.client.clone();
cx.background_spawn(async move {
let operations = operations.await;
for chunk in language::proto::split_operations(operations) {
client
.send(proto::UpdateChannelBuffer {
channel_id: channel_id.0,
operations: chunk,
})
.ok();
}
})
.detach();
cx.background_executor()
.spawn(async move {
let operations = operations.await;
for chunk in
language::proto::split_operations(operations)
{
client
.send(proto::UpdateChannelBuffer {
channel_id: channel_id.0,
operations: chunk,
})
.ok();
}
})
.detach();
return true;
}
}

View File

@@ -19,7 +19,7 @@ use futures::{
channel::oneshot, future::BoxFuture, AsyncReadExt, FutureExt, SinkExt, Stream, StreamExt,
TryFutureExt as _, TryStreamExt,
};
use gpui::{actions, App, AppContext as _, AsyncApp, Entity, Global, Task, WeakEntity};
use gpui::{actions, App, AsyncApp, Entity, Global, Task, WeakEntity};
use http_client::{AsyncBody, HttpClient, HttpClientWithUrl};
use parking_lot::RwLock;
use postage::watch;
@@ -1064,7 +1064,7 @@ impl Client {
let rpc_url = self.rpc_url(http, release_channel);
let system_id = self.telemetry.system_id();
let metrics_id = self.telemetry.metrics_id();
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
use HttpOrHttps::*;
#[derive(Debug)]
@@ -1743,7 +1743,7 @@ mod tests {
use crate::test::FakeServer;
use clock::FakeSystemClock;
use gpui::{BackgroundExecutor, TestAppContext};
use gpui::{AppContext as _, BackgroundExecutor, TestAppContext};
use http_client::FakeHttpClient;
use parking_lot::Mutex;
use proto::TypedEnvelope;
@@ -1806,7 +1806,7 @@ mod tests {
// Time out when client tries to connect.
client.override_authenticate(move |cx| {
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
Ok(Credentials {
user_id,
access_token: "token".into(),
@@ -1814,7 +1814,7 @@ mod tests {
})
});
client.override_establish_connection(|_, cx| {
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
future::pending::<()>().await;
unreachable!()
})
@@ -1848,7 +1848,7 @@ mod tests {
// Time out when re-establishing the connection.
server.allow_connections();
client.override_establish_connection(|_, cx| {
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
future::pending::<()>().await;
unreachable!()
})
@@ -1887,7 +1887,7 @@ mod tests {
move |cx| {
let auth_count = auth_count.clone();
let dropped_auth_count = dropped_auth_count.clone();
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
*auth_count.lock() += 1;
let _drop = util::defer(move || *dropped_auth_count.lock() += 1);
future::pending::<()>().await;

View File

@@ -5,7 +5,7 @@ use anyhow::Result;
use clock::SystemClock;
use futures::channel::mpsc;
use futures::{Future, StreamExt};
use gpui::{App, AppContext as _, BackgroundExecutor, Task};
use gpui::{App, BackgroundExecutor, Task};
use http_client::{self, AsyncBody, HttpClient, HttpClientWithUrl, Method, Request};
use parking_lot::Mutex;
use release_channel::ReleaseChannel;
@@ -219,17 +219,18 @@ impl Telemetry {
}));
Self::log_file_path();
cx.background_spawn({
let state = state.clone();
let os_version = os_version();
state.lock().os_version = Some(os_version.clone());
async move {
if let Some(tempfile) = File::create(Self::log_file_path()).log_err() {
state.lock().log_file = Some(tempfile);
cx.background_executor()
.spawn({
let state = state.clone();
let os_version = os_version();
state.lock().os_version = Some(os_version.clone());
async move {
if let Some(tempfile) = File::create(Self::log_file_path()).log_err() {
state.lock().log_file = Some(tempfile);
}
}
}
})
.detach();
})
.detach();
cx.observe_global::<SettingsStore>({
let state = state.clone();
@@ -251,16 +252,17 @@ impl Telemetry {
let (tx, mut rx) = mpsc::unbounded();
::telemetry::init(tx);
cx.background_spawn({
let this = Arc::downgrade(&this);
async move {
while let Some(event) = rx.next().await {
let Some(state) = this.upgrade() else { break };
state.report_event(Event::Flexible(event))
cx.background_executor()
.spawn({
let this = Arc::downgrade(&this);
async move {
while let Some(event) = rx.next().await {
let Some(state) = this.upgrade() else { break };
state.report_event(Event::Flexible(event))
}
}
}
})
.detach();
})
.detach();
// We should only ever have one instance of Telemetry, leak the subscription to keep it alive
// rather than store in TelemetryState, complicating spawn as subscriptions are not Send

View File

@@ -85,7 +85,7 @@ impl FakeServer {
Connection::in_memory(cx.background_executor().clone());
let (connection_id, io, incoming) =
peer.add_test_connection(server_conn, cx.background_executor().clone());
cx.background_spawn(io).detach();
cx.background_executor().spawn(io).detach();
{
let mut state = state.lock();
state.connection_id = Some(connection_id);

View File

@@ -229,6 +229,7 @@ impl Database {
}
/// Creates a new channel message.
#[allow(clippy::too_many_arguments)]
pub async fn create_channel_message(
&self,
channel_id: ChannelId,

View File

@@ -122,6 +122,7 @@ impl Database {
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn get_or_create_user_by_github_account_tx(
&self,
github_login: &str,

View File

@@ -289,6 +289,7 @@ impl LlmDatabase {
.await
}
#[allow(clippy::too_many_arguments)]
pub async fn record_usage(
&self,
user_id: UserId,
@@ -553,6 +554,7 @@ impl LlmDatabase {
.await
}
#[allow(clippy::too_many_arguments)]
async fn update_usage_for_measure(
&self,
user_id: UserId,

View File

@@ -33,6 +33,7 @@ pub struct LlmTokenClaims {
const LLM_TOKEN_LIFETIME: Duration = Duration::from_secs(60 * 60);
impl LlmTokenClaims {
#[allow(clippy::too_many_arguments)]
pub fn create(
user: &user::Model,
is_staff: bool,

View File

@@ -691,6 +691,7 @@ impl Server {
})
}
#[allow(clippy::too_many_arguments)]
pub fn handle_connection(
self: &Arc<Self>,
connection: Connection,
@@ -1074,6 +1075,7 @@ pub fn routes(server: Arc<Server>) -> Router<(), Body> {
.layer(Extension(server))
}
#[allow(clippy::too_many_arguments)]
pub async fn handle_websocket_request(
TypedHeader(ProtocolVersion(protocol_version)): TypedHeader<ProtocolVersion>,
app_version_header: Option<TypedHeader<AppVersionHeader>>,

View File

@@ -463,6 +463,7 @@ impl<T: RandomizedTest> TestPlan<T> {
})
}
#[allow(clippy::too_many_arguments)]
async fn apply_server_operation(
plan: Arc<Mutex<Self>>,
deterministic: BackgroundExecutor,

View File

@@ -244,17 +244,18 @@ impl TestServer {
.await
.expect("retrieving user failed")
.unwrap();
cx.background_spawn(server.handle_connection(
server_conn,
client_name,
Principal::User(user),
ZedVersion(SemanticVersion::new(1, 0, 0)),
None,
None,
Some(connection_id_tx),
Executor::Deterministic(cx.background_executor().clone()),
))
.detach();
cx.background_executor()
.spawn(server.handle_connection(
server_conn,
client_name,
Principal::User(user),
ZedVersion(SemanticVersion::new(1, 0, 0)),
None,
None,
Some(connection_id_tx),
Executor::Deterministic(cx.background_executor().clone()),
))
.detach();
let connection_id = connection_id_rx.await.map_err(|e| {
EstablishConnectionError::Other(anyhow!(
"{} (is server shutting down?)",

View File

@@ -201,7 +201,8 @@ impl ChatPanel {
) -> Task<Result<Entity<Self>>> {
cx.spawn(|mut cx| async move {
let serialized_panel = if let Some(panel) = cx
.background_spawn(async move { KEY_VALUE_STORE.read_kvp(CHAT_PANEL_KEY) })
.background_executor()
.spawn(async move { KEY_VALUE_STORE.read_kvp(CHAT_PANEL_KEY) })
.await
.log_err()
.flatten()
@@ -226,7 +227,7 @@ impl ChatPanel {
fn serialize(&mut self, cx: &mut Context<Self>) {
let width = self.width;
self.pending_serialization = cx.background_spawn(
self.pending_serialization = cx.background_executor().spawn(
async move {
KEY_VALUE_STORE
.write_kvp(

View File

@@ -454,7 +454,8 @@ impl MessageEditor {
mut cx: AsyncWindowContext,
) {
let (buffer, ranges) = cx
.background_spawn(async move {
.background_executor()
.spawn(async move {
let ranges = MENTIONS_SEARCH.search(&buffer, None).await;
(buffer, ranges)
})

View File

@@ -319,7 +319,8 @@ impl CollabPanel {
mut cx: AsyncWindowContext,
) -> anyhow::Result<Entity<Self>> {
let serialized_panel = cx
.background_spawn(async move { KEY_VALUE_STORE.read_kvp(COLLABORATION_PANEL_KEY) })
.background_executor()
.spawn(async move { KEY_VALUE_STORE.read_kvp(COLLABORATION_PANEL_KEY) })
.await
.map_err(|_| anyhow::anyhow!("Failed to read collaboration panel from key value store"))
.log_err()
@@ -350,7 +351,7 @@ impl CollabPanel {
fn serialize(&mut self, cx: &mut Context<Self>) {
let width = self.width;
let collapsed_channels = self.collapsed_channels.clone();
self.pending_serialization = cx.background_spawn(
self.pending_serialization = cx.background_executor().spawn(
async move {
KEY_VALUE_STORE
.write_kvp(
@@ -869,6 +870,7 @@ impl CollabPanel {
})
}
#[allow(clippy::too_many_arguments)]
fn render_participant_project(
&self,
project_id: u64,

View File

@@ -183,7 +183,8 @@ impl NotificationPanel {
) -> Task<Result<Entity<Self>>> {
cx.spawn(|mut cx| async move {
let serialized_panel = if let Some(panel) = cx
.background_spawn(async move { KEY_VALUE_STORE.read_kvp(NOTIFICATION_PANEL_KEY) })
.background_executor()
.spawn(async move { KEY_VALUE_STORE.read_kvp(NOTIFICATION_PANEL_KEY) })
.await
.log_err()
.flatten()
@@ -208,7 +209,7 @@ impl NotificationPanel {
fn serialize(&mut self, cx: &mut Context<Self>) {
let width = self.width;
self.pending_serialization = cx.background_spawn(
self.pending_serialization = cx.background_executor().spawn(
async move {
KEY_VALUE_STORE
.write_kvp(

View File

@@ -281,7 +281,7 @@ impl PickerDelegate for CommandPaletteDelegate {
query = alias.to_string();
}
let (mut tx, mut rx) = postage::dispatch::channel(1);
let task = cx.background_spawn({
let task = cx.background_executor().spawn({
let mut commands = self.all_commands.clone();
let hit_counts = cx.global::<HitCounts>().clone();
let executor = cx.background_executor().clone();

View File

@@ -1,7 +1,7 @@
use anyhow::{anyhow, Context as _, Result};
use collections::HashMap;
use futures::{channel::oneshot, io::BufWriter, select, AsyncRead, AsyncWrite, FutureExt};
use gpui::{AppContext as _, AsyncApp, BackgroundExecutor, Task};
use gpui::{AsyncApp, BackgroundExecutor, Task};
use parking_lot::Mutex;
use postage::barrier;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
@@ -192,7 +192,7 @@ impl Client {
let (stdout, stderr) = futures::join!(stdout_input_task, stderr_input_task);
stdout.or(stderr)
});
let output_task = cx.background_spawn({
let output_task = cx.background_executor().spawn({
Self::handle_output(
stdin,
outbound_rx,

View File

@@ -234,7 +234,8 @@ impl RegisteredBuffer {
let new_snapshot = buffer.update(&mut cx, |buffer, _| buffer.snapshot()).ok()?;
let content_changes = cx
.background_spawn({
.background_executor()
.spawn({
let new_snapshot = new_snapshot.clone();
async move {
new_snapshot
@@ -587,7 +588,8 @@ impl Copilot {
}
};
cx.background_spawn(task.map_err(|err| anyhow!("{:?}", err)))
cx.background_executor()
.spawn(task.map_err(|err| anyhow!("{:?}", err)))
} else {
// If we're downloading, wait until download is finished
// If we're in a stuck state, display to the user
@@ -599,7 +601,7 @@ impl Copilot {
self.update_sign_in_status(request::SignInStatus::NotSignedIn, cx);
if let CopilotServer::Running(RunningCopilotServer { lsp: server, .. }) = &self.server {
let server = server.clone();
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
server
.request::<request::SignOut>(request::SignOutParams {})
.await?;
@@ -629,7 +631,7 @@ impl Copilot {
cx.notify();
cx.background_spawn(start_task)
cx.background_executor().spawn(start_task)
}
pub fn language_server(&self) -> Option<&Arc<LanguageServer>> {
@@ -811,7 +813,7 @@ impl Copilot {
.request::<request::NotifyAccepted>(request::NotifyAcceptedParams {
uuid: completion.uuid.clone(),
});
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
request.await?;
Ok(())
})
@@ -835,7 +837,7 @@ impl Copilot {
.map(|completion| completion.uuid.clone())
.collect(),
});
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
request.await?;
Ok(())
})
@@ -882,7 +884,7 @@ impl Copilot {
.map(|file| file.path().to_path_buf())
.unwrap_or_default();
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let (version, snapshot) = snapshot.await?;
let result = lsp
.request::<R>(request::GetCompletionsParams {

View File

@@ -40,15 +40,13 @@ pub enum Model {
O3Mini,
#[serde(alias = "claude-3-5-sonnet", rename = "claude-3.5-sonnet")]
Claude3_5Sonnet,
#[serde(alias = "gemini-2.0-flash", rename = "gemini-2.0-flash-001")]
Gemini20Flash,
}
impl Model {
pub fn uses_streaming(&self) -> bool {
match self {
Self::Gpt4o | Self::Gpt4 | Self::Gpt3_5Turbo | Self::Claude3_5Sonnet => true,
Self::O3Mini | Self::O1 | Self::Gemini20Flash => false,
Self::O3Mini | Self::O1 => false,
}
}
@@ -60,7 +58,6 @@ impl Model {
"o1" => Ok(Self::O1),
"o3-mini" => Ok(Self::O3Mini),
"claude-3-5-sonnet" => Ok(Self::Claude3_5Sonnet),
"gemini-2.0-flash-001" => Ok(Self::Gemini20Flash),
_ => Err(anyhow!("Invalid model id: {}", id)),
}
}
@@ -73,7 +70,6 @@ impl Model {
Self::O3Mini => "o3-mini",
Self::O1 => "o1",
Self::Claude3_5Sonnet => "claude-3-5-sonnet",
Self::Gemini20Flash => "gemini-2.0-flash-001",
}
}
@@ -85,7 +81,6 @@ impl Model {
Self::O3Mini => "o3-mini",
Self::O1 => "o1",
Self::Claude3_5Sonnet => "Claude 3.5 Sonnet",
Self::Gemini20Flash => "Gemini 2.0 Flash",
}
}
@@ -97,7 +92,6 @@ impl Model {
Self::O3Mini => 20000,
Self::O1 => 20000,
Self::Claude3_5Sonnet => 200_000,
Model::Gemini20Flash => 128_000,
}
}
}

View File

@@ -4,7 +4,7 @@ pub mod query;
// Re-export
pub use anyhow;
use anyhow::Context as _;
use gpui::{App, AppContext};
use gpui::App;
pub use indoc::indoc;
pub use paths::database_dir;
pub use smol;
@@ -192,7 +192,8 @@ pub fn write_and_log<F>(cx: &App, db_write: impl FnOnce() -> F + Send + 'static)
where
F: Future<Output = anyhow::Result<()>> + Send,
{
cx.background_spawn(async move { db_write().await.log_err() })
cx.background_executor()
.spawn(async move { db_write().await.log_err() })
.detach()
}

View File

@@ -1,16 +1,14 @@
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{
div, px, uniform_list, AnyElement, BackgroundExecutor, Div, Entity, Focusable, FontWeight,
div, px, uniform_list, AnyElement, BackgroundExecutor, Div, Entity, FontWeight,
ListSizingBehavior, ScrollStrategy, SharedString, Size, StrikethroughStyle, StyledText,
UniformListScrollHandle,
UniformListScrollHandle, WeakEntity,
};
use language::Buffer;
use language::CodeLabel;
use language::{CodeLabel, CompletionDocumentation};
use lsp::LanguageServerId;
use markdown::Markdown;
use multi_buffer::{Anchor, ExcerptId};
use ordered_float::OrderedFloat;
use project::lsp_store::CompletionDocumentation;
use project::{CodeAction, Completion, TaskSourceKind};
use std::{
@@ -23,12 +21,12 @@ use std::{
use task::ResolvedTask;
use ui::{prelude::*, Color, IntoElement, ListItem, Pixels, Popover, Styled};
use util::ResultExt;
use workspace::Workspace;
use crate::hover_popover::{hover_markdown_style, open_markdown_url};
use crate::{
actions::{ConfirmCodeAction, ConfirmCompletion},
split_words, styled_runs_for_code_label, CodeActionProvider, CompletionId, CompletionProvider,
DisplayRow, Editor, EditorStyle, ResolvedTasks,
render_parsed_markdown, split_words, styled_runs_for_code_label, CodeActionProvider,
CompletionId, CompletionProvider, DisplayRow, Editor, EditorStyle, ResolvedTasks,
};
pub const MENU_GAP: Pixels = px(4.);
@@ -139,27 +137,17 @@ impl CodeContextMenu {
}
pub fn render_aside(
&mut self,
editor: &Editor,
&self,
style: &EditorStyle,
max_size: Size<Pixels>,
window: &mut Window,
workspace: Option<WeakEntity<Workspace>>,
cx: &mut Context<Editor>,
) -> Option<AnyElement> {
match self {
CodeContextMenu::Completions(menu) => menu.render_aside(editor, max_size, window, cx),
CodeContextMenu::Completions(menu) => menu.render_aside(style, max_size, workspace, cx),
CodeContextMenu::CodeActions(_) => None,
}
}
pub fn focused(&self, window: &mut Window, cx: &mut Context<Editor>) -> bool {
match self {
CodeContextMenu::Completions(completions_menu) => completions_menu
.markdown_element
.as_ref()
.is_some_and(|markdown| markdown.focus_handle(cx).contains_focused(window, cx)),
CodeContextMenu::CodeActions(_) => false,
}
}
}
pub enum ContextMenuOrigin {
@@ -181,7 +169,6 @@ pub struct CompletionsMenu {
resolve_completions: bool,
show_completion_documentation: bool,
last_rendered_range: Rc<RefCell<Option<Range<usize>>>>,
markdown_element: Option<Entity<Markdown>>,
}
impl CompletionsMenu {
@@ -212,7 +199,6 @@ impl CompletionsMenu {
scroll_handle: UniformListScrollHandle::new(),
resolve_completions: true,
last_rendered_range: RefCell::new(None).into(),
markdown_element: None,
}
}
@@ -269,7 +255,6 @@ impl CompletionsMenu {
resolve_completions: false,
show_completion_documentation: false,
last_rendered_range: RefCell::new(None).into(),
markdown_element: None,
}
}
@@ -571,10 +556,10 @@ impl CompletionsMenu {
}
fn render_aside(
&mut self,
editor: &Editor,
&self,
style: &EditorStyle,
max_size: Size<Pixels>,
window: &mut Window,
workspace: Option<WeakEntity<Workspace>>,
cx: &mut Context<Editor>,
) -> Option<AnyElement> {
if !self.show_completion_documentation {
@@ -586,35 +571,17 @@ impl CompletionsMenu {
.documentation
.as_ref()?
{
CompletionDocumentation::MultiLinePlainText(text) => div().child(text.clone()),
CompletionDocumentation::MultiLineMarkdown(parsed) if !parsed.is_empty() => {
let markdown = self.markdown_element.get_or_insert_with(|| {
cx.new(|cx| {
let languages = editor
.workspace
.as_ref()
.and_then(|(workspace, _)| workspace.upgrade())
.map(|workspace| workspace.read(cx).app_state().languages.clone());
let language = editor
.language_at(self.initial_position, cx)
.map(|l| l.name().to_proto());
Markdown::new(
SharedString::default(),
hover_markdown_style(window, cx),
languages,
language,
window,
cx,
)
.copy_code_block_buttons(false)
.open_url(open_markdown_url)
})
});
markdown.update(cx, |markdown, cx| {
markdown.reset(parsed.clone(), window, cx);
});
div().child(markdown.clone())
CompletionDocumentation::MultiLinePlainText(text) => {
div().child(SharedString::from(text.clone()))
}
CompletionDocumentation::MultiLineMarkdown(parsed) if !parsed.text.is_empty() => div()
.child(render_parsed_markdown(
"completions_markdown",
parsed,
&style,
workspace,
cx,
)),
CompletionDocumentation::MultiLineMarkdown(_) => return None,
CompletionDocumentation::SingleLine(_) => return None,
CompletionDocumentation::Undocumented => return None,

View File

@@ -113,6 +113,7 @@ pub struct DisplayMap {
}
impl DisplayMap {
#[allow(clippy::too_many_arguments)]
pub fn new(
buffer: Entity<MultiBuffer>,
font: Font,
@@ -2069,30 +2070,18 @@ pub mod tests {
)
});
// Insert two blocks in the middle of a multi-line string literal.
// The second block has zero height.
// Insert a block in the middle of a multi-line string literal
map.update(cx, |map, cx| {
map.insert_blocks(
[
BlockProperties {
placement: BlockPlacement::Below(
buffer_snapshot.anchor_before(Point::new(1, 0)),
),
height: 1,
style: BlockStyle::Sticky,
render: Arc::new(|_| div().into_any()),
priority: 0,
},
BlockProperties {
placement: BlockPlacement::Below(
buffer_snapshot.anchor_before(Point::new(2, 0)),
),
height: 0,
style: BlockStyle::Sticky,
render: Arc::new(|_| div().into_any()),
priority: 0,
},
],
[BlockProperties {
placement: BlockPlacement::Below(
buffer_snapshot.anchor_before(Point::new(1, 0)),
),
height: 1,
style: BlockStyle::Sticky,
render: Arc::new(|_| div().into_any()),
priority: 0,
}],
cx,
)
});
@@ -2777,7 +2766,6 @@ pub mod tests {
fn init_test(cx: &mut App, f: impl Fn(&mut AllLanguageSettingsContent)) {
let settings = SettingsStore::test(cx);
cx.set_global(settings);
workspace::init_settings(cx);
language::init(cx);
crate::init(cx);
Project::init_settings(cx);

View File

@@ -723,6 +723,7 @@ impl BlockMap {
self.show_excerpt_controls
}
#[allow(clippy::too_many_arguments)]
fn header_and_footer_blocks<'a, R, T>(
show_excerpt_controls: bool,
excerpt_footer_height: u32,
@@ -1720,7 +1721,6 @@ impl BlockSnapshot {
impl<'a> BlockChunks<'a> {
/// Go to the next transform
fn advance(&mut self) {
self.input_chunk = Chunk::default();
self.transforms.next(&());
while let Some(transform) = self.transforms.item() {
if transform
@@ -1748,6 +1748,7 @@ impl<'a> BlockChunks<'a> {
);
self.input_chunks.seek(start_input_row..end_input_row);
}
self.input_chunk = Chunk::default();
}
}
}
@@ -1811,6 +1812,9 @@ impl<'a> Iterator for BlockChunks<'a> {
let (mut prefix, suffix) = self.input_chunk.text.split_at(prefix_bytes);
self.input_chunk.text = suffix;
if self.output_row == transform_end {
self.advance();
}
if self.masked {
// Not great for multibyte text because to keep cursor math correct we
@@ -1820,16 +1824,10 @@ impl<'a> Iterator for BlockChunks<'a> {
prefix = &BULLETS[..bullet_len];
}
let chunk = Chunk {
Some(Chunk {
text: prefix,
..self.input_chunk.clone()
};
if self.output_row == transform_end {
self.advance();
}
Some(chunk)
})
}
}

View File

@@ -171,7 +171,7 @@ impl WrapMap {
let text_system = cx.text_system().clone();
let (font, font_size) = self.font_with_size.clone();
let task = cx.background_spawn(async move {
let task = cx.background_executor().spawn(async move {
let mut line_wrapper = text_system.line_wrapper(font, font_size);
let tab_snapshot = new_snapshot.tab_snapshot.clone();
let range = TabPoint::zero()..tab_snapshot.max_point();
@@ -255,7 +255,7 @@ impl WrapMap {
let mut snapshot = self.snapshot.clone();
let text_system = cx.text_system().clone();
let (font, font_size) = self.font_with_size.clone();
let update_task = cx.background_spawn(async move {
let update_task = cx.background_executor().spawn(async move {
let mut edits = Patch::default();
let mut line_wrapper = text_system.line_wrapper(font, font_size);
for (tab_snapshot, tab_edits) in pending_edits {

View File

@@ -80,13 +80,13 @@ use code_context_menus::{
use git::blame::GitBlame;
use gpui::{
div, impl_actions, point, prelude::*, pulsating_between, px, relative, size, Action, Animation,
AnimationExt, AnyElement, App, AsyncWindowContext, AvailableSpace, Background, Bounds,
ClipboardEntry, ClipboardItem, Context, DispatchPhase, ElementId, Entity, EntityInputHandler,
EventEmitter, FocusHandle, FocusOutEvent, Focusable, FontId, FontWeight, Global,
HighlightStyle, Hsla, InteractiveText, KeyContext, Modifiers, MouseButton, MouseDownEvent,
PaintQuad, ParentElement, Pixels, Render, SharedString, Size, Styled, StyledText, Subscription,
Task, TextStyle, TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle,
WeakEntity, WeakFocusHandle, Window,
AnimationExt, AnyElement, App, AsyncWindowContext, AvailableSpace, Bounds, ClipboardEntry,
ClipboardItem, Context, DispatchPhase, ElementId, Entity, EntityInputHandler, EventEmitter,
FocusHandle, FocusOutEvent, Focusable, FontId, FontWeight, Global, HighlightStyle, Hsla,
InteractiveText, KeyContext, Modifiers, MouseButton, MouseDownEvent, PaintQuad, ParentElement,
Pixels, Render, SharedString, Size, Styled, StyledText, Subscription, Task, TextStyle,
TextStyleRefinement, UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity,
WeakFocusHandle, Window,
};
use highlight_matching_bracket::refresh_matching_bracket_highlights;
use hover_popover::{hide_hover, HoverState};
@@ -99,14 +99,13 @@ use itertools::Itertools;
use language::{
language_settings::{self, all_language_settings, language_settings, InlayHintSettings},
markdown, point_from_lsp, AutoindentMode, BracketPair, Buffer, Capability, CharKind, CodeLabel,
CursorShape, Diagnostic, DiskState, EditPredictionsMode, EditPreview, HighlightedText,
IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection, SelectionGoal, TextObject,
TransactionId, TreeSitterOptions,
CompletionDocumentation, CursorShape, Diagnostic, DiskState, EditPredictionsMode, EditPreview,
HighlightedText, IndentKind, IndentSize, Language, OffsetRangeExt, Point, Selection,
SelectionGoal, TextObject, TransactionId, TreeSitterOptions,
};
use language::{point_to_lsp, BufferRow, CharClassifier, Runnable, RunnableRange};
use linked_editing_ranges::refresh_linked_ranges;
use mouse_context_menu::MouseContextMenu;
use persistence::DB;
pub use proposed_changes_editor::{
ProposedChangeLocation, ProposedChangesEditor, ProposedChangesEditorToolbar,
};
@@ -132,7 +131,7 @@ use multi_buffer::{
ToOffsetUtf16,
};
use project::{
lsp_store::{CompletionDocumentation, FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
lsp_store::{FormatTrigger, LspFormatTarget, OpenLspBufferHandle},
project_settings::{GitGutterSetting, ProjectSettings},
CodeAction, Completion, CompletionIntent, DocumentHighlight, InlayHint, Location, LocationLink,
PrepareRenameResponse, Project, ProjectItem, ProjectTransaction, TaskSourceKind,
@@ -172,14 +171,8 @@ use ui::{
Tooltip,
};
use util::{defer, maybe, post_inc, RangeExt, ResultExt, TryFutureExt};
use workspace::{
item::{ItemHandle, PreviewTabsSettings},
ItemId, RestoreOnStartupBehavior,
};
use workspace::{
notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt},
WorkspaceSettings,
};
use workspace::item::{ItemHandle, PreviewTabsSettings};
use workspace::notifications::{DetachAndPromptErr, NotificationId, NotifyTaskExt};
use workspace::{
searchable::SearchEvent, ItemNavHistory, SplitDirection, ViewId, Workspace, WorkspaceId,
};
@@ -206,14 +199,6 @@ pub(crate) const SCROLL_CENTER_TOP_BOTTOM_DEBOUNCE_TIMEOUT: Duration = Duration:
pub(crate) const EDIT_PREDICTION_KEY_CONTEXT: &str = "edit_prediction";
pub(crate) const EDIT_PREDICTION_CONFLICT_KEY_CONTEXT: &str = "edit_prediction_conflict";
const COLUMNAR_SELECTION_MODIFIERS: Modifiers = Modifiers {
alt: true,
shift: true,
control: false,
platform: false,
function: false,
};
pub fn render_parsed_markdown(
element_id: impl Into<ElementId>,
parsed: &language::ParsedMarkdown,
@@ -298,7 +283,6 @@ impl InlayId {
enum DocumentHighlightRead {}
enum DocumentHighlightWrite {}
enum InputComposition {}
enum SelectedTextHighlight {}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Navigated {
@@ -697,7 +681,6 @@ pub struct Editor {
next_completion_id: CompletionId,
available_code_actions: Option<(Location, Rc<[AvailableCodeAction]>)>,
code_actions_task: Option<Task<Result<()>>>,
selection_highlight_task: Option<Task<()>>,
document_highlights_task: Option<Task<()>>,
linked_editing_range_task: Option<Task<Option<()>>>,
linked_edit_ranges: linked_editing_ranges::LinkedEditingRanges,
@@ -778,7 +761,6 @@ pub struct Editor {
selection_mark_mode: bool,
toggle_fold_multiple_buffers: Task<()>,
_scroll_cursor_center_top_bottom_task: Task<()>,
serialize_selections: Task<()>,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Default)]
@@ -1402,7 +1384,6 @@ impl Editor {
code_action_providers,
available_code_actions: Default::default(),
code_actions_task: Default::default(),
selection_highlight_task: Default::default(),
document_highlights_task: Default::default(),
linked_editing_range_task: Default::default(),
pending_rename: Default::default(),
@@ -1491,7 +1472,6 @@ impl Editor {
_scroll_cursor_center_top_bottom_task: Task::ready(()),
selection_mark_mode: false,
toggle_fold_multiple_buffers: Task::ready(()),
serialize_selections: Task::ready(()),
text_style_refinement: None,
load_diff_task: load_uncommitted_diff,
};
@@ -2185,7 +2165,6 @@ impl Editor {
}
self.refresh_code_actions(window, cx);
self.refresh_document_highlights(cx);
self.refresh_selected_text_highlights(window, cx);
refresh_matching_bracket_highlights(self, window, cx);
self.update_visible_inline_completion(window, cx);
self.edit_prediction_requires_modifier_in_leading_space = true;
@@ -2198,38 +2177,9 @@ impl Editor {
self.blink_manager.update(cx, BlinkManager::pause_blinking);
cx.emit(EditorEvent::SelectionsChanged { local });
let selections = &self.selections.disjoint;
if selections.len() == 1 {
if self.selections.disjoint_anchors().len() == 1 {
cx.emit(SearchEvent::ActiveMatchChanged)
}
if local
&& self.is_singleton(cx)
&& WorkspaceSettings::get(None, cx).restore_on_startup != RestoreOnStartupBehavior::None
{
if let Some(workspace_id) = self.workspace.as_ref().and_then(|workspace| workspace.1) {
let background_executor = cx.background_executor().clone();
let editor_id = cx.entity().entity_id().as_u64() as ItemId;
let snapshot = self.buffer().read(cx).snapshot(cx);
let selections = selections.clone();
self.serialize_selections = cx.background_spawn(async move {
background_executor.timer(Duration::from_millis(100)).await;
let selections = selections
.iter()
.map(|selection| {
(
selection.start.to_offset(&snapshot),
selection.end.to_offset(&snapshot),
)
})
.collect();
DB.save_editor_selections(editor_id, workspace_id, selections)
.await
.with_context(|| format!("persisting editor selections for editor {editor_id}, workspace {workspace_id:?}"))
.log_err();
});
}
}
cx.notify();
}
@@ -2243,7 +2193,7 @@ impl Editor {
self.change_selections_inner(autoscroll, true, window, cx, change)
}
fn change_selections_inner<R>(
pub fn change_selections_inner<R>(
&mut self,
autoscroll: Option<Autoscroll>,
request_completions: bool,
@@ -4772,91 +4722,6 @@ impl Editor {
None
}
pub fn refresh_selected_text_highlights(
&mut self,
window: &mut Window,
cx: &mut Context<Editor>,
) {
self.selection_highlight_task.take();
if !EditorSettings::get_global(cx).selection_highlight {
self.clear_background_highlights::<SelectedTextHighlight>(cx);
return;
}
let debounce = EditorSettings::get_global(cx).selection_highlight_debounce;
self.selection_highlight_task = Some(cx.spawn_in(window, |editor, mut cx| async move {
cx.background_executor()
.timer(Duration::from_millis(debounce))
.await;
let Some(Some(matches_task)) = editor
.update_in(&mut cx, |editor, _, cx| {
if editor.selections.count() != 1 || editor.selections.line_mode {
editor.clear_background_highlights::<SelectedTextHighlight>(cx);
return None;
}
let selection = editor.selections.newest::<Point>(cx);
if selection.is_empty() || selection.start.row != selection.end.row {
editor.clear_background_highlights::<SelectedTextHighlight>(cx);
return None;
}
let buffer = editor.buffer().read(cx).snapshot(cx);
Some(cx.background_spawn(async move {
let mut ranges = Vec::new();
let query = buffer.text_for_range(selection.range()).collect::<String>();
for range in [buffer.anchor_before(0)..buffer.anchor_after(buffer.len())] {
for (search_buffer, search_range, excerpt_id) in
buffer.range_to_buffer_ranges(range)
{
ranges.extend(
project::search::SearchQuery::text(
query.clone(),
false,
false,
false,
Default::default(),
Default::default(),
None,
)
.unwrap()
.search(search_buffer, Some(search_range.clone()))
.await
.into_iter()
.map(|match_range| {
let start = search_buffer
.anchor_after(search_range.start + match_range.start);
let end = search_buffer
.anchor_before(search_range.start + match_range.end);
Anchor::range_in_buffer(
excerpt_id,
search_buffer.remote_id(),
start..end,
)
}),
);
}
}
ranges
}))
})
.log_err()
else {
return;
};
let matches = matches_task.await;
editor
.update_in(&mut cx, |editor, _, cx| {
editor.clear_background_highlights::<SelectedTextHighlight>(cx);
if !matches.is_empty() {
editor.highlight_background::<SelectedTextHighlight>(
&matches,
|theme| theme.editor_document_highlight_bracket_background,
cx,
)
}
})
.log_err();
}));
}
pub fn refresh_inline_completion(
&mut self,
debounce: bool,
@@ -5127,7 +4992,6 @@ impl Editor {
.contains(&target.to_display_point(&position_map.snapshot).row())
|| !self.edit_prediction_requires_modifier()
{
self.unfold_ranges(&[target..target], true, false, cx);
// Note that this is also done in vim's handler of the Tab action.
self.change_selections(
Some(Autoscroll::newest()),
@@ -5349,8 +5213,6 @@ impl Editor {
self.update_edit_prediction_preview(&modifiers, window, cx);
}
self.update_selection_mode(&modifiers, position_map, window, cx);
let mouse_position = window.mouse_position();
if !position_map.text_hitbox.is_hovered(window) {
return;
@@ -5365,32 +5227,6 @@ impl Editor {
)
}
fn update_selection_mode(
&mut self,
modifiers: &Modifiers,
position_map: &PositionMap,
window: &mut Window,
cx: &mut Context<Self>,
) {
if modifiers != &COLUMNAR_SELECTION_MODIFIERS || self.selections.pending.is_none() {
return;
}
let mouse_position = window.mouse_position();
let point_for_position = position_map.point_for_position(mouse_position);
let position = point_for_position.previous_valid;
self.select(
SelectPhase::BeginColumnar {
position,
reset: false,
goal_column: point_for_position.exact_unclipped.column(),
},
window,
cx,
);
}
fn update_edit_prediction_preview(
&mut self,
modifiers: &Modifiers,
@@ -5919,13 +5755,14 @@ impl Editor {
editor_bg_color.blend(accent_color.opacity(0.1))
}
#[allow(clippy::too_many_arguments)]
fn render_edit_prediction_cursor_popover(
&self,
min_width: Pixels,
max_width: Pixels,
cursor_point: Point,
style: &EditorStyle,
accept_keystroke: Option<&gpui::Keystroke>,
accept_keystroke: &gpui::Keystroke,
_window: &Window,
cx: &mut Context<Editor>,
) -> Option<AnyElement> {
@@ -6004,7 +5841,7 @@ impl Editor {
)
.child(Label::new("Hold").size(LabelSize::Small))
.child(h_flex().children(ui::render_modifiers(
&accept_keystroke?.modifiers,
&accept_keystroke.modifiers,
PlatformStyle::platform(),
Some(Color::Default),
Some(IconSize::Small.rems().into()),
@@ -6069,41 +5906,35 @@ impl Editor {
.overflow_hidden()
.child(completion),
)
.when_some(accept_keystroke, |el, accept_keystroke| {
if !accept_keystroke.modifiers.modified() {
return el;
}
el.child(
h_flex()
.h_full()
.border_l_1()
.rounded_r_lg()
.border_color(cx.theme().colors().border)
.bg(Self::edit_prediction_line_popover_bg_color(cx))
.gap_1()
.py_1()
.px_2()
.child(
h_flex()
.font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
.when(is_platform_style_mac, |parent| parent.gap_1())
.child(h_flex().children(ui::render_modifiers(
&accept_keystroke.modifiers,
PlatformStyle::platform(),
Some(if !has_completion {
Color::Muted
} else {
Color::Default
}),
None,
false,
))),
)
.child(Label::new("Preview").into_any_element())
.opacity(if has_completion { 1.0 } else { 0.4 }),
)
})
.child(
h_flex()
.h_full()
.border_l_1()
.rounded_r_lg()
.border_color(cx.theme().colors().border)
.bg(Self::edit_prediction_line_popover_bg_color(cx))
.gap_1()
.py_1()
.px_2()
.child(
h_flex()
.font(theme::ThemeSettings::get_global(cx).buffer_font.clone())
.when(is_platform_style_mac, |parent| parent.gap_1())
.child(h_flex().children(ui::render_modifiers(
&accept_keystroke.modifiers,
PlatformStyle::platform(),
Some(if !has_completion {
Color::Muted
} else {
Color::Default
}),
None,
false,
))),
)
.child(Label::new("Preview").into_any_element())
.opacity(if has_completion { 1.0 } else { 0.4 }),
)
.into_any(),
)
}
@@ -6220,14 +6051,19 @@ impl Editor {
}
fn render_context_menu_aside(
&mut self,
&self,
style: &EditorStyle,
max_size: Size<Pixels>,
window: &mut Window,
cx: &mut Context<Editor>,
) -> Option<AnyElement> {
self.context_menu.borrow_mut().as_mut().and_then(|menu| {
self.context_menu.borrow().as_ref().and_then(|menu| {
if menu.visible() {
menu.render_aside(self, max_size, window, cx)
menu.render_aside(
style,
max_size,
self.workspace.as_ref().map(|(w, _)| w.clone()),
cx,
)
} else {
None
}
@@ -9189,32 +9025,21 @@ impl Editor {
window: &mut Window,
cx: &mut Context<Self>,
) {
let selections = self
.selections
.all::<Point>(cx)
.into_iter()
.map(|selection| selection.start..selection.end)
.collect::<Vec<_>>();
self.unfold_ranges(&selections, true, true, cx);
let mut to_unfold = Vec::new();
let mut new_selection_ranges = Vec::new();
{
let selections = self.selections.all::<Point>(cx);
let buffer = self.buffer.read(cx).read(cx);
for selection in selections {
for row in selection.start.row..selection.end.row {
let cursor = Point::new(row, buffer.line_len(MultiBufferRow(row)));
new_selection_ranges.push(cursor..cursor);
}
let is_multiline_selection = selection.start.row != selection.end.row;
// Don't insert last one if it's a multi-line selection ending at the start of a line,
// so this action feels more ergonomic when paired with other selection operations
let should_skip_last = is_multiline_selection && selection.end.column == 0;
if !should_skip_last {
new_selection_ranges.push(selection.end..selection.end);
}
new_selection_ranges.push(selection.end..selection.end);
to_unfold.push(selection.start..selection.end);
}
}
self.unfold_ranges(&to_unfold, true, true, cx);
self.change_selections(Some(Autoscroll::fit()), window, cx, |s| {
s.select_ranges(new_selection_ranges);
});
@@ -10216,12 +10041,13 @@ impl Editor {
return;
}
let new_rows =
cx.background_spawn({
let snapshot = display_snapshot.clone();
async move {
Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
}
})
cx.background_executor()
.spawn({
let snapshot = display_snapshot.clone();
async move {
Self::fetch_runnable_ranges(&snapshot, Anchor::min()..Anchor::max())
}
})
.await;
let rows = Self::runnable_rows(project, display_snapshot, new_rows, cx.clone());
@@ -10983,7 +10809,7 @@ impl Editor {
HoverLink::InlayHint(lsp_location, server_id) => {
let computation =
self.compute_target_location(lsp_location, server_id, window, cx);
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let location = computation.await?;
Ok(TargetTaskResult::Location(location))
})
@@ -13782,14 +13608,14 @@ impl Editor {
&self,
window: &mut Window,
cx: &mut App,
) -> BTreeMap<DisplayRow, Background> {
) -> BTreeMap<DisplayRow, Hsla> {
let snapshot = self.snapshot(window, cx);
let mut used_highlight_orders = HashMap::default();
self.highlighted_rows
.iter()
.flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
.fold(
BTreeMap::<DisplayRow, Background>::new(),
BTreeMap::<DisplayRow, Hsla>::new(),
|mut unique_rows, highlight| {
let start = highlight.range.start.to_display_point(&snapshot);
let end = highlight.range.end.to_display_point(&snapshot);
@@ -13806,7 +13632,7 @@ impl Editor {
used_highlight_orders.entry(row).or_insert(highlight.index);
if highlight.index >= *used_index {
*used_index = highlight.index;
unique_rows.insert(DisplayRow(row), highlight.color.into());
unique_rows.insert(DisplayRow(row), highlight.color);
}
}
unique_rows
@@ -14920,14 +14746,8 @@ impl Editor {
if !self.hover_state.focused(window, cx) {
hide_hover(self, cx);
}
if !self
.context_menu
.borrow()
.as_ref()
.is_some_and(|context_menu| context_menu.focused(window, cx))
{
self.hide_context_menu(window, cx);
}
self.hide_context_menu(window, cx);
self.discard_inline_completion(false, cx);
cx.emit(EditorEvent::Blurred);
cx.notify();
@@ -15054,33 +14874,6 @@ impl Editor {
pub fn wait_for_diff_to_load(&self) -> Option<Shared<Task<()>>> {
self.load_diff_task.clone()
}
fn read_selections_from_db(
&mut self,
item_id: u64,
workspace_id: WorkspaceId,
window: &mut Window,
cx: &mut Context<Editor>,
) {
if !self.is_singleton(cx)
|| WorkspaceSettings::get(None, cx).restore_on_startup == RestoreOnStartupBehavior::None
{
return;
}
let Some(selections) = DB.get_editor_selections(item_id, workspace_id).log_err() else {
return;
};
if selections.is_empty() {
return;
}
let snapshot = self.buffer.read(cx).snapshot(cx);
self.change_selections(None, window, cx, |s| {
s.select_ranges(selections.into_iter().map(|(start, end)| {
snapshot.clip_offset(start, Bias::Left)..snapshot.clip_offset(end, Bias::Right)
}));
});
}
}
fn get_uncommitted_diff_for_buffer(
@@ -15589,7 +15382,7 @@ fn snippet_completions(
let scope = language.map(|language| language.default_scope());
let executor = cx.background_executor().clone();
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let classifier = CharClassifier::new(scope).for_completion(true);
let mut last_word = chars
.chars()
@@ -15676,7 +15469,7 @@ fn snippet_completions(
documentation: snippet
.description
.clone()
.map(|description| CompletionDocumentation::SingleLine(description.into())),
.map(CompletionDocumentation::SingleLine),
lsp_completion: lsp::CompletionItem {
label: snippet.prefix.first().unwrap().clone(),
kind: Some(CompletionItemKind::SNIPPET),
@@ -15719,7 +15512,7 @@ impl CompletionProvider for Entity<Project> {
self.update(cx, |project, cx| {
let snippets = snippet_completions(project, buffer, buffer_position, cx);
let project_completions = project.completions(buffer, buffer_position, options, cx);
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let mut completions = project_completions.await?;
let snippets_completions = snippets.await?;
completions.extend(snippets_completions);

View File

@@ -9,8 +9,6 @@ pub struct EditorSettings {
pub cursor_blink: bool,
pub cursor_shape: Option<CursorShape>,
pub current_line_highlight: CurrentLineHighlight,
pub selection_highlight: bool,
pub selection_highlight_debounce: u64,
pub lsp_highlight_debounce: u64,
pub hover_popover_enabled: bool,
pub hover_popover_delay: u64,
@@ -104,7 +102,6 @@ pub struct Toolbar {
pub struct Scrollbar {
pub show: ShowScrollbar,
pub git_diff: bool,
pub selected_text: bool,
pub selected_symbol: bool,
pub search_results: bool,
pub diagnostics: ScrollbarDiagnostics,
@@ -274,14 +271,6 @@ pub struct EditorSettingsContent {
///
/// Default: all
pub current_line_highlight: Option<CurrentLineHighlight>,
/// Whether to highlight all occurrences of the selected text in an editor.
///
/// Default: true
pub selection_highlight: Option<bool>,
/// The debounce delay before querying highlights based on the selected text.
///
/// Default: 75
pub selection_highlight_debounce: Option<u64>,
/// The debounce delay before querying highlights from the language
/// server based on the current cursor location.
///
@@ -415,10 +404,6 @@ pub struct ScrollbarContent {
///
/// Default: true
pub search_results: Option<bool>,
/// Whether to show selected text occurrences in the scrollbar.
///
/// Default: true
pub selected_text: Option<bool>,
/// Whether to show selected symbol occurrences in the scrollbar.
///
/// Default: true

View File

@@ -4874,76 +4874,13 @@ fn test_select_line(cx: &mut TestAppContext) {
}
#[gpui::test]
async fn test_split_selection_into_lines(cx: &mut TestAppContext) {
init_test(cx, |_| {});
let mut cx = EditorTestContext::new(cx).await;
#[track_caller]
fn test(cx: &mut EditorTestContext, initial_state: &'static str, expected_state: &'static str) {
cx.set_state(initial_state);
cx.update_editor(|e, window, cx| {
e.split_selection_into_lines(&SplitSelectionIntoLines, window, cx)
});
cx.assert_editor_state(expected_state);
}
// Selection starts and ends at the middle of lines, left-to-right
test(
&mut cx,
"aa\nb«ˇb\ncc\ndd\ne»e\nff",
"aa\nbbˇ\nccˇ\nddˇ\neˇe\nff",
);
// Same thing, right-to-left
test(
&mut cx,
"aa\nb«b\ncc\ndd\neˇ»e\nff",
"aa\nbbˇ\nccˇ\nddˇ\neˇe\nff",
);
// Whole buffer, left-to-right, last line *doesn't* end with newline
test(
&mut cx,
"«ˇaa\nbb\ncc\ndd\nee\nff»",
"aaˇ\nbbˇ\nccˇ\nddˇ\neeˇ\nffˇ",
);
// Same thing, right-to-left
test(
&mut cx,
"«aa\nbb\ncc\ndd\nee\nffˇ»",
"aaˇ\nbbˇ\nccˇ\nddˇ\neeˇ\nffˇ",
);
// Whole buffer, left-to-right, last line ends with newline
test(
&mut cx,
"«ˇaa\nbb\ncc\ndd\nee\nff\n»",
"aaˇ\nbbˇ\nccˇ\nddˇ\neeˇ\nffˇ\n",
);
// Same thing, right-to-left
test(
&mut cx,
"«aa\nbb\ncc\ndd\nee\nff\nˇ»",
"aaˇ\nbbˇ\nccˇ\nddˇ\neeˇ\nffˇ\n",
);
// Starts at the end of a line, ends at the start of another
test(
&mut cx,
"aa\nbb«ˇ\ncc\ndd\nee\n»ff\n",
"aa\nbbˇ\nccˇ\nddˇ\neeˇ\nff\n",
);
}
#[gpui::test]
async fn test_split_selection_into_lines_interacting_with_creases(cx: &mut TestAppContext) {
fn test_split_selection_into_lines(cx: &mut TestAppContext) {
init_test(cx, |_| {});
let editor = cx.add_window(|window, cx| {
let buffer = MultiBuffer::build_simple(&sample_text(9, 5, 'a'), cx);
build_editor(buffer, window, cx)
});
// setup
_ = editor.update(cx, |editor, window, cx| {
editor.fold_creases(
vec![
@@ -4955,13 +4892,6 @@ async fn test_split_selection_into_lines_interacting_with_creases(cx: &mut TestA
window,
cx,
);
assert_eq!(
editor.display_text(cx),
"aa⋯bbb\nccc⋯eeee\nfffff\nggggg\n⋯i"
);
});
_ = editor.update(cx, |editor, window, cx| {
editor.change_selections(None, window, cx, |s| {
s.select_display_ranges([
DisplayPoint::new(DisplayRow(0), 0)..DisplayPoint::new(DisplayRow(0), 1),
@@ -4970,15 +4900,28 @@ async fn test_split_selection_into_lines_interacting_with_creases(cx: &mut TestA
DisplayPoint::new(DisplayRow(4), 4)..DisplayPoint::new(DisplayRow(4), 4),
])
});
assert_eq!(
editor.display_text(cx),
"aa⋯bbb\nccc⋯eeee\nfffff\nggggg\n⋯i"
);
});
_ = editor.update(cx, |editor, window, cx| {
editor.split_selection_into_lines(&SplitSelectionIntoLines, window, cx);
assert_eq!(
editor.display_text(cx),
"aaaaa\nbbbbb\nccc⋯eeee\nfffff\nggggg\n⋯i"
);
assert_eq!(
editor.selections.display_ranges(cx),
[
DisplayPoint::new(DisplayRow(0), 1)..DisplayPoint::new(DisplayRow(0), 1),
DisplayPoint::new(DisplayRow(0), 2)..DisplayPoint::new(DisplayRow(0), 2),
DisplayPoint::new(DisplayRow(2), 0)..DisplayPoint::new(DisplayRow(2), 0),
DisplayPoint::new(DisplayRow(5), 4)..DisplayPoint::new(DisplayRow(5), 4)
]
);
});
EditorTestContext::for_editor(editor, cx)
.await
.assert_editor_state("aˇaˇaaa\nbbbbb\nˇccccc\nddddd\neeeee\nfffff\nggggg\nhhhhh\niiiiiˇ");
_ = editor.update(cx, |editor, window, cx| {
editor.change_selections(None, window, cx, |s| {
@@ -5000,15 +4943,11 @@ async fn test_split_selection_into_lines_interacting_with_creases(cx: &mut TestA
DisplayPoint::new(DisplayRow(3), 5)..DisplayPoint::new(DisplayRow(3), 5),
DisplayPoint::new(DisplayRow(4), 5)..DisplayPoint::new(DisplayRow(4), 5),
DisplayPoint::new(DisplayRow(5), 5)..DisplayPoint::new(DisplayRow(5), 5),
DisplayPoint::new(DisplayRow(6), 5)..DisplayPoint::new(DisplayRow(6), 5)
DisplayPoint::new(DisplayRow(6), 5)..DisplayPoint::new(DisplayRow(6), 5),
DisplayPoint::new(DisplayRow(7), 0)..DisplayPoint::new(DisplayRow(7), 0)
]
);
});
EditorTestContext::for_editor(editor, cx)
.await
.assert_editor_state(
"aaaaaˇ\nbbbbbˇ\ncccccˇ\ndddddˇ\neeeeeˇ\nfffffˇ\ngggggˇ\nhhhhh\niiiii",
);
}
#[gpui::test]
@@ -5017,6 +4956,7 @@ async fn test_add_selection_above_below(cx: &mut TestAppContext) {
let mut cx = EditorTestContext::new(cx).await;
// let buffer = MultiBuffer::build_simple("abc\ndefghi\n\njk\nlmno\n", cx);
cx.set_state(indoc!(
r#"abc
defˇghi
@@ -5301,39 +5241,24 @@ async fn test_select_all_matches(cx: &mut gpui::TestAppContext) {
// Test caret-only selections
cx.set_state("abc\nˇabc abc\ndefabc\nabc");
cx.update_editor(|e, window, cx| e.select_all_matches(&SelectAllMatches, window, cx))
.unwrap();
cx.assert_editor_state("«abcˇ»\n«abcˇ» «abcˇ»\ndefabc\n«abcˇ»");
// Test left-to-right selections
cx.set_state("abc\n«abcˇ»\nabc");
cx.update_editor(|e, window, cx| e.select_all_matches(&SelectAllMatches, window, cx))
.unwrap();
cx.assert_editor_state("«abcˇ»\n«abcˇ»\n«abcˇ»");
// Test right-to-left selections
cx.set_state("abc\n«ˇabc»\nabc");
cx.update_editor(|e, window, cx| e.select_all_matches(&SelectAllMatches, window, cx))
.unwrap();
cx.assert_editor_state("«ˇabc»\n«ˇabc»\n«ˇabc»");
// Test selecting whitespace with caret selection
cx.set_state("abc\nˇ abc\nabc");
cx.update_editor(|e, window, cx| e.select_all_matches(&SelectAllMatches, window, cx))
.unwrap();
cx.assert_editor_state("abc\n« ˇ»abc\nabc");
// Test selecting whitespace with left-to-right selection
cx.set_state("abc\n«ˇ »abc\nabc");
cx.update_editor(|e, window, cx| e.select_all_matches(&SelectAllMatches, window, cx))
.unwrap();
cx.assert_editor_state("abc\n«ˇ »abc\nabc");
// Test no matches with right-to-left selection
cx.set_state("abc\n« ˇ»abc\nabc");
cx.update_editor(|e, window, cx| e.select_all_matches(&SelectAllMatches, window, cx))
.unwrap();
cx.assert_editor_state("abc\n« ˇ»abc\nabc");
}
#[gpui::test]
@@ -6283,7 +6208,7 @@ async fn test_autoclose_with_embedded_language(cx: &mut gpui::TestAppContext) {
autoclose_before: "})]>".into(),
..Default::default()
},
Some(tree_sitter_html::LANGUAGE.into()),
Some(tree_sitter_html::language()),
)
.with_injection_query(
r#"
@@ -9685,7 +9610,7 @@ async fn test_toggle_block_comment(cx: &mut gpui::TestAppContext) {
block_comment: Some(("<!-- ".into(), " -->".into())),
..Default::default()
},
Some(tree_sitter_html::LANGUAGE.into()),
Some(tree_sitter_html::language()),
)
.with_injection_query(
r#"

View File

@@ -20,10 +20,9 @@ use crate::{
EditorSettings, EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GoToHunk,
GutterDimensions, HalfPageDown, HalfPageUp, HandleInput, HoveredCursor, InlineCompletion,
JumpData, LineDown, LineUp, OpenExcerpts, PageDown, PageUp, Point, RevertSelectedHunks, RowExt,
RowRangeExt, SelectPhase, SelectedTextHighlight, Selection, SoftWrap, StickyHeaderExcerpt,
ToPoint, ToggleFold, ToggleStagedSelectedDiffHunks, COLUMNAR_SELECTION_MODIFIERS,
CURSORS_VISIBLE_FOR, FILE_HEADER_HEIGHT, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN,
MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
RowRangeExt, SelectPhase, Selection, SoftWrap, StickyHeaderExcerpt, ToPoint, ToggleFold,
ToggleStagedSelectedDiffHunks, CURSORS_VISIBLE_FOR, FILE_HEADER_HEIGHT,
GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN, MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
};
use buffer_diff::{DiffHunkSecondaryStatus, DiffHunkStatus};
use client::ParticipantIndex;
@@ -32,7 +31,7 @@ use file_icons::FileIcons;
use git::{blame::BlameEntry, Oid};
use gpui::{
anchored, deferred, div, fill, linear_color_stop, linear_gradient, outline, pattern_slash,
point, px, quad, relative, size, svg, transparent_black, Action, AnyElement, App,
point, px, quad, relative, size, solid_color, svg, transparent_black, Action, AnyElement, App,
AvailableSpace, Axis, Bounds, ClickEvent, ClipboardItem, ContentMask, Context, Corner, Corners,
CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity, Focusable, FontId,
GlobalElementId, Hitbox, Hsla, InteractiveElement, IntoElement, Keystroke, Length,
@@ -80,16 +79,19 @@ use workspace::{item::Item, notifications::NotifyTaskExt, Workspace};
const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 7.;
/// Note that for a "modified" MultiBufferDiffHunk, there are two DisplayDiffHunks,
/// one for the deleted portion and one for the added portion.
#[derive(Debug, Clone, PartialEq, Eq)]
enum DisplayDiffHunk {
Folded {
display_row: DisplayRow,
},
Unfolded {
diff_base_byte_range: Range<usize>,
display_row_range: Range<DisplayRow>,
multi_buffer_range: Range<Anchor>,
status: DiffHunkStatus,
expanded: bool,
is_primary: bool,
},
}
@@ -104,7 +106,7 @@ struct SelectionLayout {
}
impl SelectionLayout {
fn new<T: ToPoint + ToDisplayPoint + Clone>(
fn new<T: multi_buffer::ToPoint + ToDisplayPoint + Clone>(
selection: Selection<T>,
line_mode: bool,
cursor_shape: CursorShape,
@@ -515,7 +517,6 @@ impl EditorElement {
if editor.hover_state.focused(window, cx) {
return;
}
editor.handle_modifiers_changed(event.modifiers, &position_map, window, cx);
})
}
@@ -595,7 +596,7 @@ impl EditorElement {
let point_for_position = position_map.point_for_position(event.position);
let position = point_for_position.previous_valid;
if modifiers == COLUMNAR_SELECTION_MODIFIERS {
if modifiers.shift && modifiers.alt {
editor.select(
SelectPhase::BeginColumnar {
position,
@@ -931,6 +932,7 @@ impl EditorElement {
cx.notify()
}
#[allow(clippy::too_many_arguments)]
fn layout_selections(
&self,
start_anchor: Anchor,
@@ -1102,6 +1104,7 @@ impl EditorElement {
cursors
}
#[allow(clippy::too_many_arguments)]
fn layout_visible_cursors(
&self,
snapshot: &EditorSnapshot,
@@ -1293,9 +1296,6 @@ impl EditorElement {
// Buffer Search Results
(is_singleton && scrollbar_settings.search_results && editor.has_background_highlights::<BufferSearchHighlights>())
||
// Selected Text Occurrences
(is_singleton && scrollbar_settings.selected_text && editor.has_background_highlights::<SelectedTextHighlight>())
||
// Selected Symbol Occurrences
(is_singleton && scrollbar_settings.selected_symbol && (editor.has_background_highlights::<DocumentHighlightRead>() || editor.has_background_highlights::<DocumentHighlightWrite>()))
||
@@ -1451,6 +1451,7 @@ impl EditorElement {
axis_pair(horizontal_scrollbar, vertical_scrollbar)
}
#[allow(clippy::too_many_arguments)]
fn prepaint_crease_toggles(
&self,
crease_toggles: &mut [Option<AnyElement>],
@@ -1485,6 +1486,7 @@ impl EditorElement {
}
}
#[allow(clippy::too_many_arguments)]
fn prepaint_crease_trailers(
&self,
trailers: Vec<Option<AnyElement>>,
@@ -1557,30 +1559,100 @@ impl EditorElement {
let hunk_end_point = Point::new(hunk.row_range.end.0, 0);
let hunk_display_start = snapshot.point_to_display_point(hunk_start_point, Bias::Left);
let hunk_added_start_at =
Anchor::in_buffer(hunk.excerpt_id, hunk.buffer_id, hunk.buffer_range.start);
let hunk_deleted_to_added_break = snapshot.point_to_display_point(
hunk_added_start_at.to_point(&snapshot.buffer_snapshot),
Bias::Right,
);
let hunk_display_end = snapshot.point_to_display_point(hunk_end_point, Bias::Right);
let display_hunk = if hunk_display_start.column() != 0 {
DisplayDiffHunk::Folded {
display_row: hunk_display_start.row(),
}
if hunk_display_start.column() != 0 {
display_hunks.push((
DisplayDiffHunk::Folded {
display_row: hunk_display_start.row(),
},
None,
));
} else {
let mut end_row = hunk_display_end.row();
if hunk_display_end.column() > 0 {
end_row.0 += 1;
}
DisplayDiffHunk::Unfolded {
status: hunk.status(),
diff_base_byte_range: hunk.diff_base_byte_range,
display_row_range: hunk_display_start.row()..end_row,
multi_buffer_range: Anchor::range_in_buffer(
hunk.excerpt_id,
hunk.buffer_id,
hunk.buffer_range,
),
let deleted_count = snapshot
.buffer_snapshot
.row_infos(hunk.row_range.start)
.take(hunk.row_range.end.0 as usize - hunk.row_range.start.0 as usize)
.take_while(|row_info| {
matches!(row_info.diff_status, Some(DiffHunkStatus::Removed(_)))
})
.count();
let has_added = snapshot
.buffer_snapshot
.row_infos(hunk.row_range.start)
.take(hunk.row_range.end.0 as usize - hunk.row_range.start.0 as usize)
.any(|row_info| matches!(row_info.diff_status, Some(DiffHunkStatus::Added(_))));
let expanded = deleted_count > 0 || has_added;
if deleted_count > 0 && has_added {
display_hunks.push((
DisplayDiffHunk::Unfolded {
status: DiffHunkStatus::Removed(hunk.secondary_status),
display_row_range: hunk_display_start.row()
..hunk_display_start.row() + DisplayRow(deleted_count as u32),
multi_buffer_range: Anchor::range_in_buffer(
hunk.excerpt_id,
hunk.buffer_id,
hunk.buffer_range.clone(),
),
expanded,
is_primary: true,
},
None,
));
display_hunks.push((
DisplayDiffHunk::Unfolded {
status: DiffHunkStatus::Added(hunk.secondary_status),
display_row_range: hunk_display_start.row()
+ DisplayRow(deleted_count as u32)
..end_row,
multi_buffer_range: Anchor::range_in_buffer(
hunk.excerpt_id,
hunk.buffer_id,
hunk.buffer_range,
),
expanded,
is_primary: false,
},
None,
));
} else {
let status = if expanded && matches!(hunk.status(), DiffHunkStatus::Modified(_))
{
if hunk_display_start.row() < hunk_deleted_to_added_break.row() {
DiffHunkStatus::Removed(hunk.secondary_status)
} else {
DiffHunkStatus::Added(hunk.secondary_status)
}
} else {
hunk.status()
};
display_hunks.push((
DisplayDiffHunk::Unfolded {
status,
display_row_range: hunk_display_start.row()..end_row,
multi_buffer_range: Anchor::range_in_buffer(
hunk.excerpt_id,
hunk.buffer_id,
hunk.buffer_range,
),
expanded,
is_primary: true,
},
None,
));
}
};
display_hunks.push((display_hunk, None));
}
let git_gutter_setting = ProjectSettings::get_global(cx)
@@ -1600,6 +1672,7 @@ impl EditorElement {
display_hunks
}
#[allow(clippy::too_many_arguments)]
fn layout_inline_blame(
&self,
display_row: DisplayRow,
@@ -1686,6 +1759,7 @@ impl EditorElement {
Some(element)
}
#[allow(clippy::too_many_arguments)]
fn layout_blame_entries(
&self,
buffer_rows: &[RowInfo],
@@ -1754,6 +1828,7 @@ impl EditorElement {
Some(shaped_lines)
}
#[allow(clippy::too_many_arguments)]
fn layout_indent_guides(
&self,
content_origin: gpui::Point<Pixels>,
@@ -1871,6 +1946,7 @@ impl EditorElement {
(offset_y, length)
}
#[allow(clippy::too_many_arguments)]
fn layout_run_indicators(
&self,
line_height: Pixels,
@@ -1914,7 +1990,8 @@ impl EditorElement {
if tasks.offset.0 < offset_range_start || tasks.offset.0 >= offset_range_end {
return None;
}
let multibuffer_point = tasks.offset.0.to_point(&snapshot.buffer_snapshot);
let multibuffer_point =
multi_buffer::ToPoint::to_point(&tasks.offset.0, &snapshot.buffer_snapshot);
let multibuffer_row = MultiBufferRow(multibuffer_point.row);
let buffer_folded = snapshot
.buffer_snapshot
@@ -1963,6 +2040,7 @@ impl EditorElement {
})
}
#[allow(clippy::too_many_arguments)]
fn layout_code_actions_indicator(
&self,
line_height: Pixels,
@@ -2061,6 +2139,7 @@ impl EditorElement {
relative_rows
}
#[allow(clippy::too_many_arguments)]
fn layout_line_numbers(
&self,
gutter_hitbox: Option<&Hitbox>,
@@ -2273,6 +2352,7 @@ impl EditorElement {
}
}
#[allow(clippy::too_many_arguments)]
fn prepaint_lines(
&self,
start_row: DisplayRow,
@@ -2299,6 +2379,7 @@ impl EditorElement {
line_elements
}
#[allow(clippy::too_many_arguments)]
fn render_block(
&self,
block: &Block,
@@ -2760,6 +2841,7 @@ impl EditorElement {
}))
}
#[allow(clippy::too_many_arguments)]
fn render_blocks(
&self,
rows: Range<DisplayRow>,
@@ -2944,6 +3026,7 @@ impl EditorElement {
/// Returns true if any of the blocks changed size since the previous frame. This will trigger
/// a restart of rendering for the editor based on the new sizes.
#[allow(clippy::too_many_arguments)]
fn layout_blocks(
&self,
blocks: &mut Vec<BlockLayout>,
@@ -2987,6 +3070,7 @@ impl EditorElement {
}
}
#[allow(clippy::too_many_arguments)]
fn layout_sticky_buffer_header(
&self,
StickyHeaderExcerpt {
@@ -3061,6 +3145,7 @@ impl EditorElement {
header
}
#[allow(clippy::too_many_arguments)]
fn layout_cursor_popovers(
&self,
line_height: Pixels,
@@ -3170,7 +3255,7 @@ impl EditorElement {
max_width,
cursor_point,
style,
accept_binding.keystroke(),
accept_binding.keystroke()?,
window,
cx,
)?;
@@ -3249,6 +3334,7 @@ impl EditorElement {
);
}
#[allow(clippy::too_many_arguments)]
fn layout_gutter_menu(
&self,
line_height: Pixels,
@@ -3301,6 +3387,7 @@ impl EditorElement {
);
}
#[allow(clippy::too_many_arguments)]
fn layout_popovers_above_or_below_line(
&self,
target_position: gpui::Point<Pixels>,
@@ -3405,6 +3492,7 @@ impl EditorElement {
Some((laid_out_popovers, y_flipped))
}
#[allow(clippy::too_many_arguments)]
fn layout_context_menu_aside(
&self,
y_flipped: bool,
@@ -3426,11 +3514,9 @@ impl EditorElement {
available_within_viewport.right - px(1.),
MENU_ASIDE_MAX_WIDTH,
);
let Some(mut aside) = self.render_context_menu_aside(
size(max_width, max_height - POPOVER_Y_PADDING),
window,
cx,
) else {
let Some(mut aside) =
self.render_context_menu_aside(size(max_width, max_height - POPOVER_Y_PADDING), cx)
else {
return;
};
aside.layout_as_root(AvailableSpace::min_size(), window, cx);
@@ -3452,7 +3538,7 @@ impl EditorElement {
),
) - POPOVER_Y_PADDING,
);
let Some(mut aside) = self.render_context_menu_aside(max_size, window, cx) else {
let Some(mut aside) = self.render_context_menu_aside(max_size, cx) else {
return;
};
let actual_size = aside.layout_as_root(AvailableSpace::min_size(), window, cx);
@@ -3493,7 +3579,7 @@ impl EditorElement {
// Skip drawing if it doesn't fit anywhere.
if let Some((aside, position)) = positioned_aside {
window.defer_draw(aside, position, 2);
window.defer_draw(aside, position, 1);
}
}
@@ -3514,18 +3600,19 @@ impl EditorElement {
fn render_context_menu_aside(
&self,
max_size: Size<Pixels>,
window: &mut Window,
cx: &mut App,
) -> Option<AnyElement> {
if max_size.width < px(100.) || max_size.height < px(12.) {
None
} else {
self.editor.update(cx, |editor, cx| {
editor.render_context_menu_aside(max_size, window, cx)
editor.render_context_menu_aside(&self.style, max_size, cx)
})
}
}
#[allow(clippy::too_many_arguments)]
fn layout_edit_prediction_popover(
&self,
text_bounds: &Bounds<Pixels>,
@@ -3982,6 +4069,7 @@ impl EditorElement {
Some(element)
}
#[allow(clippy::too_many_arguments)]
fn layout_hover_popovers(
&self,
snapshot: &EditorSnapshot,
@@ -4098,6 +4186,7 @@ impl EditorElement {
}
}
#[allow(clippy::too_many_arguments)]
fn layout_diff_hunk_controls(
&self,
row_range: Range<DisplayRow>,
@@ -4121,14 +4210,29 @@ impl EditorElement {
newest_cursor_position,
];
for (hunk, _) in display_hunks {
let mut display_hunks = display_hunks.iter().peekable();
while let Some((hunk, _)) = display_hunks.next() {
if let DisplayDiffHunk::Unfolded {
display_row_range,
multi_buffer_range,
status,
is_primary: true,
..
} = &hunk
{
let mut display_row_range = display_row_range.clone();
if let Some((
DisplayDiffHunk::Unfolded {
display_row_range: secondary_display_row_range,
is_primary: false,
..
},
_,
)) = display_hunks.peek()
{
display_row_range.end = secondary_display_row_range.end;
}
if display_row_range.start < row_range.start
|| display_row_range.start >= row_range.end
{
@@ -4178,6 +4282,7 @@ impl EditorElement {
controls
}
#[allow(clippy::too_many_arguments)]
fn layout_signature_help(
&self,
hitbox: &Hitbox,
@@ -4326,7 +4431,7 @@ impl EditorElement {
window.paint_quad(fill(Bounds { origin, size }, color));
};
let mut current_paint: Option<(gpui::Background, Range<DisplayRow>)> = None;
let mut current_paint: Option<(Hsla, Range<DisplayRow>)> = None;
for (&new_row, &new_background) in &layout.highlighted_rows {
match &mut current_paint {
Some((current_background, current_range)) => {
@@ -4524,11 +4629,17 @@ impl EditorElement {
}
}
fn paint_diff_hunks(layout: &mut EditorLayout, window: &mut Window, cx: &mut App) {
fn paint_diff_hunk_gutter_indicators(
layout: &mut EditorLayout,
window: &mut Window,
cx: &mut App,
) {
if layout.display_hunks.is_empty() {
return;
}
let corners = Corners::all(px(0.));
let line_height = layout.position_map.line_height;
window.paint_layer(layout.gutter_hitbox.bounds, |window| {
for (hunk, hitbox) in &layout.display_hunks {
@@ -4542,36 +4653,41 @@ impl EditorElement {
);
Some((
hunk_bounds,
cx.theme().status().modified,
Corners::all(px(0.)),
cx.theme().colors().version_control_modified.opacity(0.7),
corners,
&DiffHunkSecondaryStatus::None,
false,
))
}
DisplayDiffHunk::Unfolded {
status,
display_row_range,
expanded,
..
} => hitbox.as_ref().map(|hunk_hitbox| match status {
DiffHunkStatus::Added(secondary_status) => (
hunk_hitbox.bounds,
cx.theme().status().created,
Corners::all(px(0.)),
cx.theme().colors().version_control_added.opacity(0.7),
corners,
secondary_status,
*expanded,
),
DiffHunkStatus::Modified(secondary_status) => (
hunk_hitbox.bounds,
cx.theme().status().modified,
Corners::all(px(0.)),
cx.theme().colors().version_control_modified.opacity(0.7),
corners,
secondary_status,
*expanded,
),
DiffHunkStatus::Removed(secondary_status)
if !display_row_range.is_empty() =>
{
(
hunk_hitbox.bounds,
cx.theme().status().deleted,
Corners::all(px(0.)),
cx.theme().colors().version_control_deleted.opacity(0.7),
corners,
secondary_status,
*expanded,
)
}
DiffHunkStatus::Removed(secondary_status) => (
@@ -4582,23 +4698,33 @@ impl EditorElement {
),
size(hunk_hitbox.size.width * px(2.), hunk_hitbox.size.height),
),
cx.theme().status().deleted,
cx.theme().colors().version_control_deleted.opacity(0.7),
Corners::all(1. * line_height),
secondary_status,
*expanded,
),
}),
};
if let Some((hunk_bounds, mut background_color, corner_radii, secondary_status)) =
hunk_to_paint
if let Some((
hunk_bounds,
background_color,
corner_radii,
secondary_status,
expanded,
)) = hunk_to_paint
{
if *secondary_status != DiffHunkSecondaryStatus::None {
background_color.a *= 0.6;
}
let background =
if *secondary_status != DiffHunkSecondaryStatus::None && expanded {
pattern_slash(background_color, line_height.0 / 2.5)
} else {
solid_color(background_color)
};
window.paint_quad(quad(
hunk_bounds,
corner_radii,
background_color,
background,
Edges::default(),
transparent_black(),
));
@@ -4726,7 +4852,7 @@ impl EditorElement {
)
});
if show_git_gutter {
Self::paint_diff_hunks(layout, window, cx)
Self::paint_diff_hunk_gutter_indicators(layout, window, cx)
}
let highlight_width = 0.275 * layout.position_map.line_height;
@@ -5266,7 +5392,8 @@ impl EditorElement {
Some(cx.spawn_in(window, |editor, mut cx| async move {
let scrollbar_size = scrollbar_layout.hitbox.size;
let scrollbar_markers = cx
.background_spawn(async move {
.background_executor()
.spawn(async move {
let max_point = snapshot.display_snapshot.buffer_snapshot.max_point();
let mut marker_quads = Vec::new();
if scrollbar_settings.git_diff {
@@ -5284,9 +5411,15 @@ impl EditorElement {
end_display_row.0 -= 1;
}
let color = match &hunk.status() {
DiffHunkStatus::Added(_) => theme.status().created,
DiffHunkStatus::Modified(_) => theme.status().modified,
DiffHunkStatus::Removed(_) => theme.status().deleted,
DiffHunkStatus::Added(_) => {
theme.colors().version_control_added
}
DiffHunkStatus::Modified(_) => {
theme.colors().version_control_modified
}
DiffHunkStatus::Removed(_) => {
theme.colors().version_control_deleted
}
};
ColoredRange {
start: start_display_row,
@@ -5306,14 +5439,11 @@ impl EditorElement {
{
let is_search_highlights = *background_highlight_id
== TypeId::of::<BufferSearchHighlights>();
let is_text_highlights = *background_highlight_id
== TypeId::of::<SelectedTextHighlight>();
let is_symbol_occurrences = *background_highlight_id
== TypeId::of::<DocumentHighlightRead>()
|| *background_highlight_id
== TypeId::of::<DocumentHighlightWrite>();
if (is_search_highlights && scrollbar_settings.search_results)
|| (is_text_highlights && scrollbar_settings.selected_text)
|| (is_symbol_occurrences && scrollbar_settings.selected_symbol)
{
let mut color = theme.status().info;
@@ -5416,6 +5546,7 @@ impl EditorElement {
});
}
#[allow(clippy::too_many_arguments)]
fn paint_highlighted_range(
&self,
range: Range<DisplayPoint>,
@@ -5830,6 +5961,7 @@ impl AcceptEditPredictionBinding {
}
}
#[allow(clippy::too_many_arguments)]
fn prepaint_gutter_button(
button: IconButton,
row: DisplayRow,
@@ -6069,6 +6201,7 @@ impl fmt::Debug for LineFragment {
}
impl LineWithInvisibles {
#[allow(clippy::too_many_arguments)]
fn from_chunks<'a>(
chunks: impl Iterator<Item = HighlightedChunk<'a>>,
editor_style: &EditorStyle,
@@ -6273,6 +6406,7 @@ impl LineWithInvisibles {
layouts
}
#[allow(clippy::too_many_arguments)]
fn prepaint(
&mut self,
line_height: Pixels,
@@ -6307,6 +6441,7 @@ impl LineWithInvisibles {
}
}
#[allow(clippy::too_many_arguments)]
fn draw(
&self,
layout: &EditorLayout,
@@ -6350,6 +6485,7 @@ impl LineWithInvisibles {
);
}
#[allow(clippy::too_many_arguments)]
fn draw_invisibles(
&self,
selection_ranges: &[Range<DisplayPoint>],
@@ -6864,39 +7000,17 @@ impl Element for EditorElement {
)
};
let (mut highlighted_rows, distinguish_unstaged_hunks) =
self.editor.update(cx, |editor, cx| {
(
editor.highlighted_display_rows(window, cx),
editor.distinguish_unstaged_diff_hunks,
)
});
let mut highlighted_rows = self
.editor
.update(cx, |editor, cx| editor.highlighted_display_rows(window, cx));
for (ix, row_info) in row_infos.iter().enumerate() {
let background = match row_info.diff_status {
Some(DiffHunkStatus::Added(secondary_status)) => {
let color = style.status.created_background;
match secondary_status {
DiffHunkSecondaryStatus::HasSecondaryHunk
| DiffHunkSecondaryStatus::OverlapsWithSecondaryHunk
if distinguish_unstaged_hunks =>
{
pattern_slash(color, line_height.0 / 4.0)
}
_ => color.into(),
}
Some(DiffHunkStatus::Added(_)) => {
cx.theme().colors().version_control_added_background
}
Some(DiffHunkStatus::Removed(secondary_status)) => {
let color = style.status.deleted_background;
match secondary_status {
DiffHunkSecondaryStatus::HasSecondaryHunk
| DiffHunkSecondaryStatus::OverlapsWithSecondaryHunk
if distinguish_unstaged_hunks =>
{
pattern_slash(color, line_height.0 / 4.0)
}
_ => color.into(),
}
Some(DiffHunkStatus::Removed(_)) => {
cx.theme().colors().version_control_deleted_background
}
_ => continue,
};
@@ -7679,6 +7793,7 @@ struct ScrollbarRangeData {
}
impl ScrollbarRangeData {
#[allow(clippy::too_many_arguments)]
pub fn new(
scrollbar_bounds: Bounds<Pixels>,
letter_size: Size<Pixels>,
@@ -7743,7 +7858,7 @@ pub struct EditorLayout {
indent_guides: Option<Vec<IndentGuideLayout>>,
visible_display_row_range: Range<DisplayRow>,
active_rows: BTreeMap<DisplayRow, bool>,
highlighted_rows: BTreeMap<DisplayRow, gpui::Background>,
highlighted_rows: BTreeMap<DisplayRow, Hsla>,
line_elements: SmallVec<[AnyElement; 1]>,
line_numbers: Arc<HashMap<MultiBufferRow, LineNumberLayout>>,
display_hunks: Vec<(DisplayDiffHunk, Option<Hitbox>)>,

View File

@@ -4,7 +4,7 @@ use git::{
blame::{Blame, BlameEntry},
parse_git_remote_url, GitHostingProvider, GitHostingProviderRegistry, Oid,
};
use gpui::{App, AppContext as _, Context, Entity, Subscription, Task};
use gpui::{App, Context, Entity, Subscription, Task};
use http_client::HttpClient;
use language::{markdown, Bias, Buffer, BufferSnapshot, Edit, LanguageRegistry, ParsedMarkdown};
use multi_buffer::RowInfo;
@@ -360,7 +360,8 @@ impl GitBlame {
self.task = cx.spawn(|this, mut cx| async move {
let result = cx
.background_spawn({
.background_executor()
.spawn({
let snapshot = snapshot.clone();
async move {
let Some(Blame {
@@ -548,7 +549,7 @@ async fn parse_markdown(text: &str, language_registry: &Arc<LanguageRegistry>) -
#[cfg(test)]
mod tests {
use super::*;
use gpui::Context;
use gpui::{AppContext as _, Context};
use language::{Point, Rope};
use project::FakeFs;
use rand::prelude::*;

View File

@@ -1,7 +1,7 @@
use crate::{
display_map::{invisibles::is_invisible, InlayOffset, ToDisplayPoint},
hover_links::{InlayHighlight, RangeInEditor},
scroll::{Autoscroll, ScrollAmount},
scroll::ScrollAmount,
Anchor, AnchorRangeExt, DisplayPoint, DisplayRow, Editor, EditorSettings, EditorSnapshot,
Hover,
};
@@ -18,14 +18,12 @@ use markdown::{Markdown, MarkdownStyle};
use multi_buffer::ToOffset;
use project::{HoverBlock, HoverBlockKind, InlayHintLabelPart};
use settings::Settings;
use std::rc::Rc;
use std::{borrow::Cow, cell::RefCell};
use std::{ops::Range, sync::Arc, time::Duration};
use std::{path::PathBuf, rc::Rc};
use theme::ThemeSettings;
use ui::{prelude::*, theme_is_transparent, Scrollbar, ScrollbarState};
use url::Url;
use util::TryFutureExt;
use workspace::Workspace;
pub const HOVER_REQUEST_DELAY_MILLIS: u64 = 200;
pub const MIN_POPOVER_CHARACTER_WIDTH: f32 = 20.;
@@ -358,15 +356,7 @@ fn show_hover(
},
..Default::default()
};
Markdown::new_text(
SharedString::new(text),
markdown_style.clone(),
None,
None,
window,
cx,
)
.open_url(open_markdown_url)
Markdown::new_text(text, markdown_style.clone(), None, None, window, cx)
})
.ok();
@@ -568,122 +558,69 @@ async fn parse_blocks(
let rendered_block = cx
.new_window_entity(|window, cx| {
let settings = ThemeSettings::get_global(cx);
let ui_font_family = settings.ui_font.family.clone();
let ui_font_fallbacks = settings.ui_font.fallbacks.clone();
let buffer_font_family = settings.buffer_font.family.clone();
let buffer_font_fallbacks = settings.buffer_font.fallbacks.clone();
let mut base_text_style = window.text_style();
base_text_style.refine(&TextStyleRefinement {
font_family: Some(ui_font_family.clone()),
font_fallbacks: ui_font_fallbacks,
color: Some(cx.theme().colors().editor_foreground),
..Default::default()
});
let markdown_style = MarkdownStyle {
base_text_style,
code_block: StyleRefinement::default().my(rems(1.)).font_buffer(cx),
inline_code: TextStyleRefinement {
background_color: Some(cx.theme().colors().background),
font_family: Some(buffer_font_family),
font_fallbacks: buffer_font_fallbacks,
..Default::default()
},
rule_color: cx.theme().colors().border,
block_quote_border_color: Color::Muted.color(cx),
block_quote: TextStyleRefinement {
color: Some(Color::Muted.color(cx)),
..Default::default()
},
link: TextStyleRefinement {
color: Some(cx.theme().colors().editor_foreground),
underline: Some(gpui::UnderlineStyle {
thickness: px(1.),
color: Some(cx.theme().colors().editor_foreground),
wavy: false,
}),
..Default::default()
},
syntax: cx.theme().syntax().clone(),
selection_background_color: { cx.theme().players().local().selection },
heading: StyleRefinement::default()
.font_weight(FontWeight::BOLD)
.text_base()
.mt(rems(1.))
.mb_0(),
};
Markdown::new(
combined_text.into(),
hover_markdown_style(window, cx),
combined_text,
markdown_style.clone(),
Some(language_registry.clone()),
fallback_language_name,
window,
cx,
)
.copy_code_block_buttons(false)
.open_url(open_markdown_url)
})
.ok();
rendered_block
}
pub fn hover_markdown_style(window: &Window, cx: &App) -> MarkdownStyle {
let settings = ThemeSettings::get_global(cx);
let ui_font_family = settings.ui_font.family.clone();
let ui_font_fallbacks = settings.ui_font.fallbacks.clone();
let buffer_font_family = settings.buffer_font.family.clone();
let buffer_font_fallbacks = settings.buffer_font.fallbacks.clone();
let mut base_text_style = window.text_style();
base_text_style.refine(&TextStyleRefinement {
font_family: Some(ui_font_family.clone()),
font_fallbacks: ui_font_fallbacks,
color: Some(cx.theme().colors().editor_foreground),
..Default::default()
});
MarkdownStyle {
base_text_style,
code_block: StyleRefinement::default().my(rems(1.)).font_buffer(cx),
inline_code: TextStyleRefinement {
background_color: Some(cx.theme().colors().background),
font_family: Some(buffer_font_family),
font_fallbacks: buffer_font_fallbacks,
..Default::default()
},
rule_color: cx.theme().colors().border,
block_quote_border_color: Color::Muted.color(cx),
block_quote: TextStyleRefinement {
color: Some(Color::Muted.color(cx)),
..Default::default()
},
link: TextStyleRefinement {
color: Some(cx.theme().colors().editor_foreground),
underline: Some(gpui::UnderlineStyle {
thickness: px(1.),
color: Some(cx.theme().colors().editor_foreground),
wavy: false,
}),
..Default::default()
},
syntax: cx.theme().syntax().clone(),
selection_background_color: { cx.theme().players().local().selection },
heading: StyleRefinement::default()
.font_weight(FontWeight::BOLD)
.text_base()
.mt(rems(1.))
.mb_0(),
}
}
pub fn open_markdown_url(link: SharedString, window: &mut Window, cx: &mut App) {
if let Ok(uri) = Url::parse(&link) {
if uri.scheme() == "file" {
if let Some(workspace) = window.root::<Workspace>().flatten() {
workspace.update(cx, |workspace, cx| {
let task =
workspace.open_abs_path(PathBuf::from(uri.path()), false, window, cx);
cx.spawn_in(window, |_, mut cx| async move {
let item = task.await?;
// Ruby LSP uses URLs with #L1,1-4,4
// we'll just take the first number and assume it's a line number
let Some(fragment) = uri.fragment() else {
return anyhow::Ok(());
};
let mut accum = 0u32;
for c in fragment.chars() {
if c >= '0' && c <= '9' && accum < u32::MAX / 2 {
accum *= 10;
accum += c as u32 - '0' as u32;
} else if accum > 0 {
break;
}
}
if accum == 0 {
return Ok(());
}
let Some(editor) = cx.update(|_, cx| item.act_as::<Editor>(cx))? else {
return Ok(());
};
editor.update_in(&mut cx, |editor, window, cx| {
editor.change_selections(
Some(Autoscroll::fit()),
window,
cx,
|selections| {
selections.select_ranges([text::Point::new(accum - 1, 0)
..text::Point::new(accum - 1, 0)]);
},
);
})
})
.detach_and_log_err(cx);
});
return;
}
}
}
cx.open_url(&link);
}
#[derive(Default, Debug)]
pub struct HoverState {
pub info_popovers: Vec<InfoPopover>,

View File

@@ -1,7 +1,7 @@
use collections::{HashMap, HashSet};
use git::diff::DiffHunkStatus;
use gpui::{
Action, AppContext as _, Corner, CursorStyle, Focusable as _, Hsla, Model, MouseButton,
Action, AppContext, Corner, CursorStyle, Focusable as _, Hsla, Model, MouseButton,
Subscription, Task,
};
use language::{Buffer, BufferId, Point};
@@ -372,7 +372,7 @@ impl Editor {
self.diff_map
.hunk_update_tasks
.insert(None, cx.background_spawn(new_toggle_task));
.insert(None, cx.background_executor().spawn(new_toggle_task));
}
pub(super) fn expand_diff_hunk(
@@ -1089,9 +1089,10 @@ impl Editor {
.ok();
});
diff_map
.hunk_update_tasks
.insert(Some(buffer_id), cx.background_spawn(new_sync_task));
diff_map.hunk_update_tasks.insert(
Some(buffer_id),
cx.background_executor().spawn(new_sync_task),
);
}
fn go_to_subsequent_hunk(

View File

@@ -1,7 +1,7 @@
use std::{ops::Range, time::Duration};
use collections::HashSet;
use gpui::{App, AppContext as _, Context, Task, Window};
use gpui::{App, Context, Task, Window};
use language::language_settings::language_settings;
use multi_buffer::{IndentGuide, MultiBufferRow};
use text::{LineIndent, Point};
@@ -102,7 +102,9 @@ impl Editor {
let snapshot = snapshot.clone();
let task = cx.background_spawn(resolve_indented_range(snapshot, cursor_row));
let task = cx
.background_executor()
.spawn(resolve_indented_range(snapshot, cursor_row));
// Try to resolve the indent in a short amount of time, otherwise move it to a background task.
match cx
@@ -113,7 +115,7 @@ impl Editor {
Err(future) => {
state.pending_refresh =
Some(cx.spawn_in(window, |editor, mut cx| async move {
let result = cx.background_spawn(future).await;
let result = cx.background_executor().spawn(future).await;
editor
.update(&mut cx, |editor, _| {
editor.active_indent_guides_state.active_indent_range = result;

View File

@@ -19,7 +19,7 @@ use crate::{
use anyhow::Context as _;
use clock::Global;
use futures::future;
use gpui::{AppContext as _, AsyncApp, Context, Entity, Task, Window};
use gpui::{AsyncApp, Context, Entity, Task, Window};
use language::{language_settings::InlayHintKind, Buffer, BufferSnapshot};
use parking_lot::RwLock;
use project::{InlayHint, ResolveState};
@@ -996,17 +996,19 @@ fn fetch_and_update_hints(
let background_task_buffer_snapshot = buffer_snapshot.clone();
let background_fetch_range = fetch_range.clone();
let new_update = cx.background_spawn(async move {
calculate_hint_updates(
query.excerpt_id,
invalidate,
background_fetch_range,
new_hints,
&background_task_buffer_snapshot,
cached_excerpt_hints,
&visible_hints,
)
})
let new_update = cx
.background_executor()
.spawn(async move {
calculate_hint_updates(
query.excerpt_id,
invalidate,
background_fetch_range,
new_hints,
&background_task_buffer_snapshot,
cached_excerpt_hints,
&visible_hints,
)
})
.await;
if let Some(new_update) = new_update {
log::debug!(

View File

@@ -706,10 +706,6 @@ impl Item for Editor {
self.buffer.read(cx).is_singleton()
}
fn can_save_as(&self, cx: &App) -> bool {
self.buffer.read(cx).is_singleton()
}
fn clone_on_split(
&self,
_workspace_id: Option<WorkspaceId>,
@@ -1073,16 +1069,12 @@ impl SerializableItem for Editor {
buffer.set_language(Some(language), cx);
}
buffer.set_text(contents, cx);
if let Some(entry) = buffer.peek_undo_stack() {
buffer.forget_transaction(entry.transaction_id());
}
})?;
cx.update(|window, cx| {
cx.new(|cx| {
let mut editor = Editor::for_buffer(buffer, Some(project), window, cx);
editor.read_selections_from_db(item_id, workspace_id, window, cx);
editor.read_scroll_position_from_db(item_id, workspace_id, window, cx);
editor
})
@@ -1130,9 +1122,6 @@ impl SerializableItem for Editor {
);
}
buffer.set_text(buffer_text, cx);
if let Some(entry) = buffer.peek_undo_stack() {
buffer.forget_transaction(entry.transaction_id());
}
})?;
}
@@ -1141,12 +1130,6 @@ impl SerializableItem for Editor {
let mut editor =
Editor::for_buffer(buffer, Some(project), window, cx);
editor.read_selections_from_db(
item_id,
workspace_id,
window,
cx,
);
editor.read_scroll_position_from_db(
item_id,
workspace_id,
@@ -1165,7 +1148,6 @@ impl SerializableItem for Editor {
window.spawn(cx, |mut cx| async move {
let editor = open_by_abs_path?.await?.downcast::<Editor>().with_context(|| format!("Failed to downcast to Editor after opening abs path {abs_path:?}"))?;
editor.update_in(&mut cx, |editor, window, cx| {
editor.read_selections_from_db(item_id, workspace_id, window, cx);
editor.read_scroll_position_from_db(item_id, workspace_id, window, cx);
})?;
Ok(editor)
@@ -1225,27 +1207,28 @@ impl SerializableItem for Editor {
let snapshot = buffer.read(cx).snapshot();
Some(cx.spawn_in(window, |_this, cx| async move {
cx.background_spawn(async move {
let (contents, language) = if serialize_dirty_buffers && is_dirty {
let contents = snapshot.text();
let language = snapshot.language().map(|lang| lang.name().to_string());
(Some(contents), language)
} else {
(None, None)
};
cx.background_executor()
.spawn(async move {
let (contents, language) = if serialize_dirty_buffers && is_dirty {
let contents = snapshot.text();
let language = snapshot.language().map(|lang| lang.name().to_string());
(Some(contents), language)
} else {
(None, None)
};
let editor = SerializedEditor {
abs_path,
contents,
language,
mtime,
};
DB.save_serialized_editor(item_id, workspace_id, editor)
.await
.context("failed to save serialized editor")
})
.await
.context("failed to save contents of buffer")?;
let editor = SerializedEditor {
abs_path,
contents,
language,
mtime,
};
DB.save_serialized_editor(item_id, workspace_id, editor)
.await
.context("failed to save serialized editor")
})
.await
.context("failed to save contents of buffer")?;
Ok(())
}))
@@ -1539,7 +1522,7 @@ impl SearchableItem for Editor {
ranges.iter().cloned().collect::<Vec<_>>()
});
cx.background_spawn(async move {
cx.background_executor().spawn(async move {
let mut ranges = Vec::new();
let search_within_ranges = if search_within_ranges.is_empty() {

View File

@@ -154,6 +154,11 @@ pub fn deploy_context_menu(
let focus = window.focused(cx);
let has_reveal_target = editor.target_file(cx).is_some();
let reveal_in_finder_label = if cfg!(target_os = "macos") {
"Reveal in Finder"
} else {
"Reveal in File Manager"
};
let has_selections = editor
.selections
.all::<PointUtf16>(cx)
@@ -191,22 +196,14 @@ pub fn deploy_context_menu(
.action("Paste", Box::new(Paste))
.separator()
.map(|builder| {
let reveal_in_finder_label = if cfg!(target_os = "macos") {
"Reveal in Finder"
} else {
"Reveal in File Manager"
};
const OPEN_IN_TERMINAL_LABEL: &str = "Open in Terminal";
if has_reveal_target {
builder
.action(reveal_in_finder_label, Box::new(RevealInFileManager))
.action(OPEN_IN_TERMINAL_LABEL, Box::new(OpenInTerminal))
builder.action(reveal_in_finder_label, Box::new(RevealInFileManager))
} else {
builder
.disabled_action(reveal_in_finder_label, Box::new(RevealInFileManager))
.disabled_action(OPEN_IN_TERMINAL_LABEL, Box::new(OpenInTerminal))
}
})
.action("Open in Terminal", Box::new(OpenInTerminal))
.map(|builder| {
const COPY_PERMALINK_LABEL: &str = "Copy Permalink";
if has_git_repo {

View File

@@ -1184,7 +1184,6 @@ mod tests {
fn init_test(cx: &mut gpui::App) {
let settings_store = SettingsStore::test(cx);
cx.set_global(settings_store);
workspace::init_settings(cx);
theme::init(theme::LoadThemes::JustBase, cx);
language::init(cx);
crate::init(cx);

View File

@@ -2,7 +2,6 @@ use anyhow::Result;
use db::sqlez::bindable::{Bind, Column, StaticColumnCount};
use db::sqlez::statement::Statement;
use fs::MTime;
use itertools::Itertools as _;
use std::path::PathBuf;
use db::sqlez_macros::sql;
@@ -135,26 +134,9 @@ define_connection!(
ALTER TABLE editors ADD COLUMN mtime_seconds INTEGER DEFAULT NULL;
ALTER TABLE editors ADD COLUMN mtime_nanos INTEGER DEFAULT NULL;
),
sql! (
CREATE TABLE editor_selections (
item_id INTEGER NOT NULL,
editor_id INTEGER NOT NULL,
workspace_id INTEGER NOT NULL,
start INTEGER NOT NULL,
end INTEGER NOT NULL,
PRIMARY KEY(item_id),
FOREIGN KEY(editor_id, workspace_id) REFERENCES editors(item_id, workspace_id)
ON DELETE CASCADE
) STRICT;
),
];
);
// https://www.sqlite.org/limits.html
// > <..> the maximum value of a host parameter number is SQLITE_MAX_VARIABLE_NUMBER,
// > which defaults to <..> 32766 for SQLite versions after 3.32.0.
const MAX_QUERY_PLACEHOLDERS: usize = 32000;
impl EditorDb {
query! {
pub fn get_serialized_editor(item_id: ItemId, workspace_id: WorkspaceId) -> Result<Option<SerializedEditor>> {
@@ -206,68 +188,6 @@ impl EditorDb {
}
}
query! {
pub fn get_editor_selections(
editor_id: ItemId,
workspace_id: WorkspaceId
) -> Result<Vec<(usize, usize)>> {
SELECT start, end
FROM editor_selections
WHERE editor_id = ?1 AND workspace_id = ?2
}
}
pub async fn save_editor_selections(
&self,
editor_id: ItemId,
workspace_id: WorkspaceId,
selections: Vec<(usize, usize)>,
) -> Result<()> {
let mut first_selection;
let mut last_selection = 0_usize;
for (count, placeholders) in std::iter::once("(?1, ?2, ?, ?)")
.cycle()
.take(selections.len())
.chunks(MAX_QUERY_PLACEHOLDERS / 4)
.into_iter()
.map(|chunk| {
let mut count = 0;
let placeholders = chunk
.inspect(|_| {
count += 1;
})
.join(", ");
(count, placeholders)
})
.collect::<Vec<_>>()
{
first_selection = last_selection;
last_selection = last_selection + count;
let query = format!(
r#"
DELETE FROM editor_selections WHERE editor_id = ?1 AND workspace_id = ?2;
INSERT OR IGNORE INTO editor_selections (editor_id, workspace_id, start, end)
VALUES {placeholders};
"#
);
let selections = selections[first_selection..last_selection].to_vec();
self.write(move |conn| {
let mut statement = Statement::prepare(conn, query)?;
statement.bind(&editor_id, 1)?;
let mut next_index = statement.bind(&workspace_id, 2)?;
for (start, end) in selections {
next_index = statement.bind(&start, next_index)?;
next_index = statement.bind(&end, next_index)?;
}
statement.exec()
})
.await?;
}
Ok(())
}
pub async fn delete_unloaded_items(
&self,
workspace: WorkspaceId,

View File

@@ -224,6 +224,7 @@ impl ScrollManager {
self.anchor.scroll_position(snapshot)
}
#[allow(clippy::too_many_arguments)]
fn set_scroll_position(
&mut self,
scroll_position: gpui::Point<f32>,
@@ -298,6 +299,7 @@ impl ScrollManager {
);
}
#[allow(clippy::too_many_arguments)]
fn set_anchor(
&mut self,
anchor: ScrollAnchor,

View File

@@ -1,6 +1,6 @@
use crate::Editor;
use gpui::{App, AppContext as _, Task as AsyncTask, Window};
use gpui::{App, Task as AsyncTask, Window};
use project::Location;
use task::{TaskContext, TaskVariables, VariableName};
use text::{ToOffset, ToPoint};
@@ -88,6 +88,7 @@ pub fn task_context(
};
editor.update(cx, |editor, cx| {
let context_task = task_context_with_editor(editor, window, cx);
cx.background_spawn(async move { context_task.await.unwrap_or_default() })
cx.background_executor()
.spawn(async move { context_task.await.unwrap_or_default() })
})
}

View File

@@ -215,8 +215,6 @@ impl EditorLspTestContext {
("[" @open "]" @close)
("{" @open "}" @close)
("<" @open ">" @close)
("'" @open "'" @close)
("`" @open "`" @close)
("\"" @open "\"" @close)"#})),
indents: Some(Cow::from(indoc! {r#"
[
@@ -254,7 +252,7 @@ impl EditorLspTestContext {
word_characters: ['-'].into_iter().collect(),
..Default::default()
},
Some(tree_sitter_html::LANGUAGE.into()),
Some(tree_sitter_html::language()),
)
.with_queries(LanguageQueries {
brackets: Some(Cow::from(indoc! {r#"

View File

@@ -399,6 +399,7 @@ async fn run_evaluation(
}
}
#[allow(clippy::too_many_arguments)]
async fn run_eval_project(
evaluation_project: EvaluationProject,
user_store: &Entity<UserStore>,

View File

@@ -168,7 +168,7 @@ impl ExtensionBuilder {
let wasm_bytes = fs::read(&wasm_path)
.with_context(|| format!("failed to read output module `{}`", wasm_path.display()))?;
let mut encoder = ComponentEncoder::default()
let encoder = ComponentEncoder::default()
.module(&wasm_bytes)?
.adapter("wasi_snapshot_preview1", &adapter_bytes)
.context("failed to load adapter module")?

View File

@@ -96,8 +96,6 @@ impl ExtensionHostProxy {
}
pub trait ExtensionThemeProxy: Send + Sync + 'static {
fn set_extensions_loaded(&self);
fn list_theme_names(&self, theme_path: PathBuf, fs: Arc<dyn Fs>) -> Task<Result<Vec<String>>>;
fn remove_user_themes(&self, themes: Vec<SharedString>);
@@ -125,14 +123,6 @@ pub trait ExtensionThemeProxy: Send + Sync + 'static {
}
impl ExtensionThemeProxy for ExtensionHostProxy {
fn set_extensions_loaded(&self) {
let Some(proxy) = self.theme_proxy.read().clone() else {
return;
};
proxy.set_extensions_loaded()
}
fn list_theme_names(&self, theme_path: PathBuf, fs: Arc<dyn Fs>) -> Task<Result<Vec<String>>> {
let Some(proxy) = self.theme_proxy.read().clone() else {
return Task::ready(Ok(Vec::new()));

View File

@@ -191,7 +191,7 @@ static mut EXTENSION: Option<Box<dyn Extension>> = None;
pub static ZED_API_VERSION: [u8; 6] = *include_bytes!(concat!(env!("OUT_DIR"), "/version_bytes"));
mod wit {
#![allow(clippy::missing_safety_doc)]
#![allow(clippy::too_many_arguments, clippy::missing_safety_doc)]
wit_bindgen::generate!({
skip: ["init-extension"],

Some files were not shown because too many files have changed in this diff Show More