Compare commits
14 commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
6d9215d937 | ||
![]() |
65f9c336bf | ||
![]() |
0cb77b04d6 | ||
![]() |
d404cc6355 | ||
![]() |
3214a069cd | ||
![]() |
d5d0c6602f | ||
![]() |
6c3706add8 | ||
![]() |
fa604153d9 | ||
![]() |
e602221dd3 | ||
![]() |
d9006fa718 | ||
![]() |
dfa6e96c2d | ||
![]() |
69dfe70ea8 | ||
![]() |
1f0cf01771 | ||
![]() |
fbbf5a5c19 |
39 changed files with 1220 additions and 435 deletions
480
Cargo.lock
generated
480
Cargo.lock
generated
|
@ -177,6 +177,28 @@ version = "0.1.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd"
|
||||
|
||||
[[package]]
|
||||
name = "alsa"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8512c9117059663fb5606788fbca3619e2a91dac0e3fe516242eab1fa6be5e44"
|
||||
dependencies = [
|
||||
"alsa-sys",
|
||||
"bitflags",
|
||||
"libc",
|
||||
"nix",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "alsa-sys"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db8fee663d06c4e303404ef5f40488a53e062f89ba8bfed81f42325aafad1527"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ambient-authority"
|
||||
version = "0.0.1"
|
||||
|
@ -590,6 +612,19 @@ dependencies = [
|
|||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "audio"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"collections",
|
||||
"gpui",
|
||||
"log",
|
||||
"parking_lot 0.11.2",
|
||||
"rodio",
|
||||
"util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "auto_update"
|
||||
version = "0.1.0"
|
||||
|
@ -756,6 +791,26 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.64.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"peeking_take_while",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bindgen"
|
||||
version = "0.65.1"
|
||||
|
@ -857,7 +912,7 @@ checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7"
|
|||
dependencies = [
|
||||
"borsh-derive-internal",
|
||||
"borsh-schema-derive-internal",
|
||||
"proc-macro-crate",
|
||||
"proc-macro-crate 0.1.5",
|
||||
"proc-macro2",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
@ -986,6 +1041,7 @@ version = "0.1.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"async-broadcast",
|
||||
"audio",
|
||||
"client",
|
||||
"collections",
|
||||
"fs",
|
||||
|
@ -1082,6 +1138,12 @@ dependencies = [
|
|||
"jobserver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cesu8"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
|
@ -1155,7 +1217,7 @@ dependencies = [
|
|||
"bitflags",
|
||||
"clap_derive 3.2.25",
|
||||
"clap_lex 0.2.4",
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"once_cell",
|
||||
"strsim",
|
||||
"termcolor",
|
||||
|
@ -1226,6 +1288,12 @@ version = "0.5.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
|
||||
|
||||
[[package]]
|
||||
name = "claxon"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bfbf56724aa9eca8afa4fcfadeb479e722935bb2a0900c2d37e0cc477af0688"
|
||||
|
||||
[[package]]
|
||||
name = "cli"
|
||||
version = "0.1.0"
|
||||
|
@ -1337,6 +1405,7 @@ version = "0.15.0"
|
|||
dependencies = [
|
||||
"anyhow",
|
||||
"async-tungstenite",
|
||||
"audio",
|
||||
"axum",
|
||||
"axum-extra",
|
||||
"base64 0.13.1",
|
||||
|
@ -1444,6 +1513,16 @@ version = "1.0.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||
|
||||
[[package]]
|
||||
name = "combine"
|
||||
version = "4.6.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "35ed6e9d84f0b51a7f52daf1c7d71dd136fd7a3f41a8462b8cdb8c78d920fad4"
|
||||
dependencies = [
|
||||
"bytes 1.4.0",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "command_palette"
|
||||
version = "0.1.0"
|
||||
|
@ -1540,11 +1619,17 @@ name = "core-foundation"
|
|||
version = "0.9.3"
|
||||
source = "git+https://github.com/servo/core-foundation-rs?rev=079665882507dd5e2ff77db3de5070c1f6c0fb85#079665882507dd5e2ff77db3de5070c1f6c0fb85"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"core-foundation-sys 0.8.3",
|
||||
"libc",
|
||||
"uuid 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.3"
|
||||
|
@ -1594,6 +1679,51 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coreaudio-rs"
|
||||
version = "0.11.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb17e2d1795b1996419648915df94bc7103c28f7b48062d7acf4652fc371b2ff"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation-sys 0.6.2",
|
||||
"coreaudio-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "coreaudio-sys"
|
||||
version = "0.2.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f034b2258e6c4ade2f73bf87b21047567fb913ee9550837c2316d139b0262b24"
|
||||
dependencies = [
|
||||
"bindgen 0.64.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpal"
|
||||
version = "0.15.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d959d90e938c5493000514b446987c07aed46c668faaa7d34d6c7a67b1a578c"
|
||||
dependencies = [
|
||||
"alsa",
|
||||
"core-foundation-sys 0.8.3",
|
||||
"coreaudio-rs",
|
||||
"dasp_sample",
|
||||
"jni 0.19.0",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"mach2",
|
||||
"ndk",
|
||||
"ndk-context",
|
||||
"oboe",
|
||||
"once_cell",
|
||||
"parking_lot 0.12.1",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"windows 0.46.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpp_demangle"
|
||||
version = "0.3.5"
|
||||
|
@ -1924,6 +2054,12 @@ dependencies = [
|
|||
"parking_lot_core 0.9.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dasp_sample"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c87e182de0887fd5361989c677c4e8f5000cd9491d6d563161a8f3a5519fc7f"
|
||||
|
||||
[[package]]
|
||||
name = "data-url"
|
||||
version = "0.1.1"
|
||||
|
@ -2233,6 +2369,12 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1"
|
||||
|
||||
[[package]]
|
||||
name = "erased-serde"
|
||||
version = "0.3.25"
|
||||
|
@ -2793,7 +2935,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
|
||||
dependencies = [
|
||||
"fallible-iterator",
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
|
@ -2889,7 +3031,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"async-task",
|
||||
"backtrace",
|
||||
"bindgen",
|
||||
"bindgen 0.65.1",
|
||||
"block",
|
||||
"cc",
|
||||
"cocoa",
|
||||
|
@ -2961,7 +3103,7 @@ dependencies = [
|
|||
"futures-sink",
|
||||
"futures-util",
|
||||
"http",
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util 0.7.8",
|
||||
|
@ -2995,6 +3137,12 @@ dependencies = [
|
|||
"ahash 0.8.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.8.1"
|
||||
|
@ -3105,6 +3253,12 @@ dependencies = [
|
|||
"digest 0.10.6",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hound"
|
||||
version = "3.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d13cdbd5dbb29f9c88095bbdc2590c9cba0d0a1269b983fef6b2cdd7e9f4db1"
|
||||
|
||||
[[package]]
|
||||
name = "http"
|
||||
version = "0.2.9"
|
||||
|
@ -3213,11 +3367,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"core-foundation-sys 0.8.3",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows",
|
||||
"windows 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3287,6 +3441,16 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.14.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "1.0.9"
|
||||
|
@ -3459,6 +3623,40 @@ dependencies = [
|
|||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.19.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec"
|
||||
dependencies = [
|
||||
"cesu8",
|
||||
"combine",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "039022cdf4d7b1cf548d31f60ae783138e5fd42013f6271049d7df7afadef96c"
|
||||
dependencies = [
|
||||
"cesu8",
|
||||
"combine",
|
||||
"jni-sys",
|
||||
"log",
|
||||
"thiserror",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jni-sys"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130"
|
||||
|
||||
[[package]]
|
||||
name = "jobserver"
|
||||
version = "0.1.26"
|
||||
|
@ -3661,6 +3859,17 @@ version = "0.2.5"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
|
||||
|
||||
[[package]]
|
||||
name = "lewton"
|
||||
version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "777b48df9aaab155475a83a7df3070395ea1ac6902f5cd062b8f2b028075c030"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"ogg",
|
||||
"tinyvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.144"
|
||||
|
@ -3893,6 +4102,15 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mach2"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
|
@ -3949,7 +4167,7 @@ name = "media"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bindgen",
|
||||
"bindgen 0.65.1",
|
||||
"block",
|
||||
"bytes 1.4.0",
|
||||
"core-foundation",
|
||||
|
@ -4207,6 +4425,35 @@ dependencies = [
|
|||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "451422b7e4718271c8b5b3aadf5adedba43dc76312454b387e98fae0fc951aa0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"jni-sys",
|
||||
"ndk-sys",
|
||||
"num_enum",
|
||||
"raw-window-handle",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ndk-context"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
|
||||
|
||||
[[package]]
|
||||
name = "ndk-sys"
|
||||
version = "0.4.1+23.1.7779620"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cf2aae958bd232cac5069850591667ad422d263686d75b52a065f9badeee5a3"
|
||||
dependencies = [
|
||||
"jni-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.38"
|
||||
|
@ -4314,6 +4561,17 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
|
@ -4366,6 +4624,27 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
|
||||
dependencies = [
|
||||
"num_enum_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_enum_derive"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
|
||||
dependencies = [
|
||||
"proc-macro-crate 1.3.1",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nvim-rs"
|
||||
version = "0.5.0"
|
||||
|
@ -4408,7 +4687,7 @@ checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424"
|
|||
dependencies = [
|
||||
"crc32fast",
|
||||
"hashbrown 0.11.2",
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"memchr",
|
||||
]
|
||||
|
||||
|
@ -4421,6 +4700,38 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oboe"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8868cc237ee02e2d9618539a23a8d228b9bb3fc2e7a5b11eed3831de77c395d0"
|
||||
dependencies = [
|
||||
"jni 0.20.0",
|
||||
"ndk",
|
||||
"ndk-context",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"oboe-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "oboe-sys"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f44155e7fb718d3cfddcf70690b2b51ac4412f347cd9e4fbe511abe9cd7b5f2"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ogg"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6951b4e8bf21c8193da321bcce9c9dd2e13c858fe078bf9054a288b419ae5d6e"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
|
@ -4710,7 +5021,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4"
|
||||
dependencies = [
|
||||
"fixedbitset",
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -4787,7 +5098,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "9bd9647b268a3d3e14ff09c23201133a62589c658db02bb7388c7246aafe0590"
|
||||
dependencies = [
|
||||
"base64 0.21.0",
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"line-wrap",
|
||||
"quick-xml",
|
||||
"serde",
|
||||
|
@ -4920,6 +5231,16 @@ dependencies = [
|
|||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-crate"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"toml_edit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
|
@ -5331,6 +5652,12 @@ dependencies = [
|
|||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "raw-window-handle"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9"
|
||||
|
||||
[[package]]
|
||||
name = "rayon"
|
||||
version = "1.7.0"
|
||||
|
@ -5614,6 +5941,19 @@ dependencies = [
|
|||
"rmp",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rodio"
|
||||
version = "0.17.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bdf1d4dea18dff2e9eb6dca123724f8b60ef44ad74a9ad283cdfe025df7e73fa"
|
||||
dependencies = [
|
||||
"claxon",
|
||||
"cpal",
|
||||
"hound",
|
||||
"lewton",
|
||||
"symphonia",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rope"
|
||||
version = "0.1.0"
|
||||
|
@ -6115,7 +6455,7 @@ checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254"
|
|||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"core-foundation-sys 0.8.3",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
@ -6126,7 +6466,7 @@ version = "2.8.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"core-foundation-sys 0.8.3",
|
||||
"libc",
|
||||
]
|
||||
|
||||
|
@ -6200,7 +6540,7 @@ version = "1.0.96"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"itoa 1.0.6",
|
||||
"ryu",
|
||||
"serde",
|
||||
|
@ -6212,7 +6552,7 @@ version = "0.1.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7d7b9ce5b0a63c6269b9623ed828b39259545a6ec0d8a35d6135ad6af6232add"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"itoa 0.4.8",
|
||||
"ryu",
|
||||
"serde",
|
||||
|
@ -6247,7 +6587,7 @@ version = "0.8.26"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"ryu",
|
||||
"serde",
|
||||
"yaml-rust",
|
||||
|
@ -6621,7 +6961,7 @@ dependencies = [
|
|||
"hex",
|
||||
"hkdf",
|
||||
"hmac 0.12.1",
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"itoa 1.0.6",
|
||||
"libc",
|
||||
"libsqlite3-sys",
|
||||
|
@ -6772,6 +7112,56 @@ dependencies = [
|
|||
"siphasher",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62e48dba70095f265fdb269b99619b95d04c89e619538138383e63310b14d941"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"symphonia-bundle-mp3",
|
||||
"symphonia-core",
|
||||
"symphonia-metadata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-bundle-mp3"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0f31d7fece546f1e6973011a9eceae948133bbd18fd3d52f6073b1e38ae6368a"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"symphonia-core",
|
||||
"symphonia-metadata",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-core"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7c73eb88fee79705268cc7b742c7bc93a7b76e092ab751d0833866970754142"
|
||||
dependencies = [
|
||||
"arrayvec 0.7.2",
|
||||
"bitflags",
|
||||
"bytemuck",
|
||||
"lazy_static",
|
||||
"log",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "symphonia-metadata"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "89c3e1937e31d0e068bbe829f66b2f2bfaa28d056365279e0ef897172c3320c0"
|
||||
dependencies = [
|
||||
"encoding_rs",
|
||||
"lazy_static",
|
||||
"log",
|
||||
"symphonia-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.109"
|
||||
|
@ -6817,7 +7207,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "a902e9050fca0a5d6877550b769abd2bd1ce8c04634b941dbe2809735e1a1e33"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"core-foundation-sys",
|
||||
"core-foundation-sys 0.8.3",
|
||||
"libc",
|
||||
"ntapi 0.4.1",
|
||||
"once_cell",
|
||||
|
@ -6986,7 +7376,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"fs",
|
||||
"gpui",
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"parking_lot 0.11.2",
|
||||
"schemars",
|
||||
"serde",
|
||||
|
@ -7292,6 +7682,23 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.19.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7"
|
||||
dependencies = [
|
||||
"indexmap 2.0.0",
|
||||
"toml_datetime",
|
||||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tonic"
|
||||
version = "0.6.2"
|
||||
|
@ -7331,7 +7738,7 @@ checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c"
|
|||
dependencies = [
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"pin-project",
|
||||
"pin-project-lite 0.2.9",
|
||||
"rand 0.8.5",
|
||||
|
@ -8188,7 +8595,7 @@ version = "0.85.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "570460c58b21e9150d2df0eaaedbb7816c34bcec009ae0dcc976e40ba81463e7"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -8202,7 +8609,7 @@ dependencies = [
|
|||
"backtrace",
|
||||
"bincode",
|
||||
"cfg-if 1.0.0",
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
|
@ -8276,7 +8683,7 @@ dependencies = [
|
|||
"anyhow",
|
||||
"cranelift-entity",
|
||||
"gimli 0.26.2",
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"log",
|
||||
"more-asserts",
|
||||
"object 0.28.4",
|
||||
|
@ -8346,7 +8753,7 @@ dependencies = [
|
|||
"backtrace",
|
||||
"cc",
|
||||
"cfg-if 1.0.0",
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"libc",
|
||||
"log",
|
||||
"mach",
|
||||
|
@ -8602,6 +9009,15 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.46.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25"
|
||||
dependencies = [
|
||||
"windows-targets 0.42.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.48.0"
|
||||
|
@ -8758,6 +9174,15 @@ version = "0.48.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.10.1"
|
||||
|
@ -8909,7 +9334,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "zed"
|
||||
version = "0.93.0"
|
||||
version = "0.93.4"
|
||||
dependencies = [
|
||||
"activity_indicator",
|
||||
"ai",
|
||||
|
@ -8918,6 +9343,7 @@ dependencies = [
|
|||
"async-recursion 0.3.2",
|
||||
"async-tar",
|
||||
"async-trait",
|
||||
"audio",
|
||||
"auto_update",
|
||||
"backtrace",
|
||||
"breadcrumbs",
|
||||
|
@ -8947,7 +9373,7 @@ dependencies = [
|
|||
"gpui",
|
||||
"ignore",
|
||||
"image",
|
||||
"indexmap",
|
||||
"indexmap 1.9.3",
|
||||
"install_cli",
|
||||
"isahc",
|
||||
"journal",
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
members = [
|
||||
"crates/activity_indicator",
|
||||
"crates/ai",
|
||||
"crates/audio",
|
||||
"crates/auto_update",
|
||||
"crates/breadcrumbs",
|
||||
"crates/call",
|
||||
|
|
|
@ -24,9 +24,7 @@
|
|||
],
|
||||
"ctrl-shift-down": "editor::AddSelectionBelow",
|
||||
"ctrl-shift-up": "editor::AddSelectionAbove",
|
||||
"cmd-shift-backspace": "editor::DeleteToBeginningOfLine",
|
||||
"cmd-shift-enter": "editor::NewlineAbove",
|
||||
"cmd-enter": "editor::NewlineBelow"
|
||||
"cmd-shift-backspace": "editor::DeleteToBeginningOfLine"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -24,9 +24,7 @@
|
|||
"ctrl-.": "editor::GoToHunk",
|
||||
"ctrl-,": "editor::GoToPrevHunk",
|
||||
"ctrl-backspace": "editor::DeleteToPreviousWordStart",
|
||||
"ctrl-delete": "editor::DeleteToNextWordEnd",
|
||||
"cmd-shift-enter": "editor::NewlineAbove",
|
||||
"cmd-enter": "editor::NewlineBelow"
|
||||
"ctrl-delete": "editor::DeleteToNextWordEnd"
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
|
@ -12,8 +12,6 @@
|
|||
"ctrl-shift-d": "editor::DuplicateLine",
|
||||
"cmd-b": "editor::GoToDefinition",
|
||||
"cmd-j": "editor::ScrollCursorCenter",
|
||||
"cmd-alt-enter": "editor::NewlineAbove",
|
||||
"cmd-enter": "editor::NewlineBelow",
|
||||
"cmd-shift-l": "editor::SelectLine",
|
||||
"cmd-shift-t": "outline::Toggle",
|
||||
"alt-backspace": "editor::DeleteToPreviousWordStart",
|
||||
|
@ -56,7 +54,9 @@
|
|||
},
|
||||
{
|
||||
"context": "Editor && mode == full",
|
||||
"bindings": {}
|
||||
"bindings": {
|
||||
"cmd-alt-enter": "editor::NewlineAbove"
|
||||
}
|
||||
},
|
||||
{
|
||||
"context": "BufferSearchBar",
|
||||
|
|
BIN
assets/sounds/joined_call.wav
Normal file
BIN
assets/sounds/joined_call.wav
Normal file
Binary file not shown.
BIN
assets/sounds/leave_call.wav
Normal file
BIN
assets/sounds/leave_call.wav
Normal file
Binary file not shown.
BIN
assets/sounds/mute.wav
Normal file
BIN
assets/sounds/mute.wav
Normal file
Binary file not shown.
BIN
assets/sounds/start_screenshare.wav
Normal file
BIN
assets/sounds/start_screenshare.wav
Normal file
Binary file not shown.
BIN
assets/sounds/stop_screenshare.wav
Normal file
BIN
assets/sounds/stop_screenshare.wav
Normal file
Binary file not shown.
BIN
assets/sounds/unmute.wav
Normal file
BIN
assets/sounds/unmute.wav
Normal file
Binary file not shown.
|
@ -147,8 +147,9 @@ impl AssistantPanel {
|
|||
.await
|
||||
.log_err()
|
||||
.unwrap_or_default();
|
||||
this.update(&mut cx, |this, _| {
|
||||
this.saved_conversations = saved_conversations
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.saved_conversations = saved_conversations;
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
|
23
crates/audio/Cargo.toml
Normal file
23
crates/audio/Cargo.toml
Normal file
|
@ -0,0 +1,23 @@
|
|||
[package]
|
||||
name = "audio"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
path = "src/audio.rs"
|
||||
doctest = false
|
||||
|
||||
[dependencies]
|
||||
gpui = { path = "../gpui" }
|
||||
collections = { path = "../collections" }
|
||||
util = { path = "../util" }
|
||||
|
||||
rodio = "0.17.1"
|
||||
|
||||
log.workspace = true
|
||||
|
||||
anyhow.workspace = true
|
||||
parking_lot.workspace = true
|
||||
|
||||
[dev-dependencies]
|
44
crates/audio/src/assets.rs
Normal file
44
crates/audio/src/assets.rs
Normal file
|
@ -0,0 +1,44 @@
|
|||
use std::{io::Cursor, sync::Arc};
|
||||
|
||||
use anyhow::Result;
|
||||
use collections::HashMap;
|
||||
use gpui::{AppContext, AssetSource};
|
||||
use rodio::{
|
||||
source::{Buffered, SamplesConverter},
|
||||
Decoder, Source,
|
||||
};
|
||||
|
||||
type Sound = Buffered<SamplesConverter<Decoder<Cursor<Vec<u8>>>, f32>>;
|
||||
|
||||
pub struct SoundRegistry {
|
||||
cache: Arc<parking_lot::Mutex<HashMap<String, Sound>>>,
|
||||
assets: Box<dyn AssetSource>,
|
||||
}
|
||||
|
||||
impl SoundRegistry {
|
||||
pub fn new(source: impl AssetSource) -> Arc<Self> {
|
||||
Arc::new(Self {
|
||||
cache: Default::default(),
|
||||
assets: Box::new(source),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn global(cx: &AppContext) -> Arc<Self> {
|
||||
cx.global::<Arc<Self>>().clone()
|
||||
}
|
||||
|
||||
pub fn get(&self, name: &str) -> Result<impl Source<Item = f32>> {
|
||||
if let Some(wav) = self.cache.lock().get(name) {
|
||||
return Ok(wav.clone());
|
||||
}
|
||||
|
||||
let path = format!("sounds/{}.wav", name);
|
||||
let bytes = self.assets.load(&path)?.into_owned();
|
||||
let cursor = Cursor::new(bytes);
|
||||
let source = Decoder::new(cursor)?.convert_samples::<f32>().buffered();
|
||||
|
||||
self.cache.lock().insert(name.to_string(), source.clone());
|
||||
|
||||
Ok(source)
|
||||
}
|
||||
}
|
67
crates/audio/src/audio.rs
Normal file
67
crates/audio/src/audio.rs
Normal file
|
@ -0,0 +1,67 @@
|
|||
use assets::SoundRegistry;
|
||||
use gpui::{AppContext, AssetSource};
|
||||
use rodio::{OutputStream, OutputStreamHandle};
|
||||
use util::ResultExt;
|
||||
|
||||
mod assets;
|
||||
|
||||
pub fn init(source: impl AssetSource, cx: &mut AppContext) {
|
||||
cx.set_global(SoundRegistry::new(source));
|
||||
cx.set_global(Audio::new());
|
||||
}
|
||||
|
||||
pub enum Sound {
|
||||
Joined,
|
||||
Leave,
|
||||
Mute,
|
||||
Unmute,
|
||||
StartScreenshare,
|
||||
StopScreenshare,
|
||||
}
|
||||
|
||||
impl Sound {
|
||||
fn file(&self) -> &'static str {
|
||||
match self {
|
||||
Self::Joined => "joined_call",
|
||||
Self::Leave => "leave_call",
|
||||
Self::Mute => "mute",
|
||||
Self::Unmute => "unmute",
|
||||
Self::StartScreenshare => "start_screenshare",
|
||||
Self::StopScreenshare => "stop_screenshare",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Audio {
|
||||
_output_stream: Option<OutputStream>,
|
||||
output_handle: Option<OutputStreamHandle>,
|
||||
}
|
||||
|
||||
impl Audio {
|
||||
pub fn new() -> Self {
|
||||
let (_output_stream, output_handle) = OutputStream::try_default().log_err().unzip();
|
||||
|
||||
Self {
|
||||
_output_stream,
|
||||
output_handle,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn play_sound(sound: Sound, cx: &AppContext) {
|
||||
if !cx.has_global::<Self>() {
|
||||
return;
|
||||
}
|
||||
|
||||
let this = cx.global::<Self>();
|
||||
|
||||
let Some(output_handle) = this.output_handle.as_ref() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let Some(source) = SoundRegistry::global(cx).get(sound.file()).log_err() else {
|
||||
return;
|
||||
};
|
||||
|
||||
output_handle.play_raw(source).log_err();
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ test-support = [
|
|||
]
|
||||
|
||||
[dependencies]
|
||||
audio = { path = "../audio" }
|
||||
client = { path = "../client" }
|
||||
collections = { path = "../collections" }
|
||||
gpui = { path = "../gpui" }
|
||||
|
|
|
@ -3,6 +3,7 @@ use crate::{
|
|||
IncomingCall,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use audio::{Audio, Sound};
|
||||
use client::{
|
||||
proto::{self, PeerId},
|
||||
Client, TypedEnvelope, User, UserStore,
|
||||
|
@ -151,6 +152,7 @@ impl Room {
|
|||
let connect = room.connect(&connection_info.server_url, &connection_info.token);
|
||||
cx.spawn(|this, mut cx| async move {
|
||||
connect.await?;
|
||||
|
||||
this.update(&mut cx, |this, cx| this.share_microphone(cx))
|
||||
.await?;
|
||||
|
||||
|
@ -176,6 +178,8 @@ impl Room {
|
|||
let maintain_connection =
|
||||
cx.spawn_weak(|this, cx| Self::maintain_connection(this, client.clone(), cx).log_err());
|
||||
|
||||
Audio::play_sound(Sound::Joined, cx);
|
||||
|
||||
Self {
|
||||
id,
|
||||
live_kit: live_kit_room,
|
||||
|
@ -265,6 +269,7 @@ impl Room {
|
|||
room.apply_room_update(room_proto, cx)?;
|
||||
anyhow::Ok(())
|
||||
})?;
|
||||
|
||||
Ok(room)
|
||||
})
|
||||
}
|
||||
|
@ -306,6 +311,8 @@ impl Room {
|
|||
}
|
||||
}
|
||||
|
||||
Audio::play_sound(Sound::Leave, cx);
|
||||
|
||||
self.status = RoomStatus::Offline;
|
||||
self.remote_participants.clear();
|
||||
self.pending_participants.clear();
|
||||
|
@ -656,6 +663,8 @@ impl Room {
|
|||
},
|
||||
);
|
||||
|
||||
Audio::play_sound(Sound::Joined, cx);
|
||||
|
||||
if let Some(live_kit) = this.live_kit.as_ref() {
|
||||
let video_tracks =
|
||||
live_kit.room.remote_video_tracks(&user.id.to_string());
|
||||
|
@ -922,6 +931,7 @@ impl Room {
|
|||
cx.spawn(|this, mut cx| async move {
|
||||
let project =
|
||||
Project::remote(id, client, user_store, language_registry, fs, cx.clone()).await?;
|
||||
|
||||
this.update(&mut cx, |this, cx| {
|
||||
this.joined_projects.retain(|project| {
|
||||
if let Some(project) = project.upgrade(cx) {
|
||||
|
@ -1212,6 +1222,9 @@ impl Room {
|
|||
};
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
Audio::play_sound(Sound::StartScreenshare, cx);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Err(error) => {
|
||||
|
@ -1227,38 +1240,20 @@ impl Room {
|
|||
})
|
||||
})
|
||||
}
|
||||
fn set_mute(
|
||||
live_kit: &mut LiveKitRoom,
|
||||
should_mute: bool,
|
||||
cx: &mut ModelContext<Self>,
|
||||
) -> Result<Task<Result<()>>> {
|
||||
if !should_mute {
|
||||
// clear user muting state.
|
||||
live_kit.muted_by_user = false;
|
||||
}
|
||||
match &mut live_kit.microphone_track {
|
||||
LocalTrack::None => Err(anyhow!("microphone was not shared")),
|
||||
LocalTrack::Pending { muted, .. } => {
|
||||
*muted = should_mute;
|
||||
cx.notify();
|
||||
Ok(Task::Ready(Some(Ok(()))))
|
||||
}
|
||||
LocalTrack::Published {
|
||||
track_publication,
|
||||
muted,
|
||||
} => {
|
||||
*muted = should_mute;
|
||||
cx.notify();
|
||||
Ok(cx.background().spawn(track_publication.set_mute(*muted)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toggle_mute(&mut self, cx: &mut ModelContext<Self>) -> Result<Task<Result<()>>> {
|
||||
let should_mute = !self.is_muted();
|
||||
if let Some(live_kit) = self.live_kit.as_mut() {
|
||||
let ret = Self::set_mute(live_kit, should_mute, cx);
|
||||
let (ret_task, old_muted) = live_kit.set_mute(should_mute, cx)?;
|
||||
live_kit.muted_by_user = should_mute;
|
||||
ret
|
||||
|
||||
if old_muted == true && live_kit.deafened == true {
|
||||
if let Some(task) = self.toggle_deafen(cx).ok() {
|
||||
task.detach();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ret_task)
|
||||
} else {
|
||||
Err(anyhow!("LiveKit not started"))
|
||||
}
|
||||
|
@ -1274,7 +1269,7 @@ impl Room {
|
|||
// When deafening, mute user's mic as well.
|
||||
// When undeafening, unmute user's mic unless it was manually muted prior to deafening.
|
||||
if live_kit.deafened || !live_kit.muted_by_user {
|
||||
mute_task = Some(Self::set_mute(live_kit, live_kit.deafened, cx)?);
|
||||
mute_task = Some(live_kit.set_mute(live_kit.deafened, cx)?.0);
|
||||
};
|
||||
for participant in self.remote_participants.values() {
|
||||
for track in live_kit
|
||||
|
@ -1319,6 +1314,8 @@ impl Room {
|
|||
} => {
|
||||
live_kit.room.unpublish_track(track_publication);
|
||||
cx.notify();
|
||||
|
||||
Audio::play_sound(Sound::StopScreenshare, cx);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1347,6 +1344,51 @@ struct LiveKitRoom {
|
|||
_maintain_tracks: [Task<()>; 2],
|
||||
}
|
||||
|
||||
impl LiveKitRoom {
|
||||
fn set_mute(
|
||||
self: &mut LiveKitRoom,
|
||||
should_mute: bool,
|
||||
cx: &mut ModelContext<Room>,
|
||||
) -> Result<(Task<Result<()>>, bool)> {
|
||||
if !should_mute {
|
||||
// clear user muting state.
|
||||
self.muted_by_user = false;
|
||||
}
|
||||
|
||||
let (result, old_muted) = match &mut self.microphone_track {
|
||||
LocalTrack::None => Err(anyhow!("microphone was not shared")),
|
||||
LocalTrack::Pending { muted, .. } => {
|
||||
let old_muted = *muted;
|
||||
*muted = should_mute;
|
||||
cx.notify();
|
||||
Ok((Task::Ready(Some(Ok(()))), old_muted))
|
||||
}
|
||||
LocalTrack::Published {
|
||||
track_publication,
|
||||
muted,
|
||||
} => {
|
||||
let old_muted = *muted;
|
||||
*muted = should_mute;
|
||||
cx.notify();
|
||||
Ok((
|
||||
cx.background().spawn(track_publication.set_mute(*muted)),
|
||||
old_muted,
|
||||
))
|
||||
}
|
||||
}?;
|
||||
|
||||
if old_muted != should_mute {
|
||||
if should_mute {
|
||||
Audio::play_sound(Sound::Mute, cx);
|
||||
} else {
|
||||
Audio::play_sound(Sound::Unmute, cx);
|
||||
}
|
||||
}
|
||||
|
||||
Ok((result, old_muted))
|
||||
}
|
||||
}
|
||||
|
||||
enum LocalTrack {
|
||||
None,
|
||||
Pending {
|
||||
|
|
|
@ -14,6 +14,7 @@ name = "seed"
|
|||
required-features = ["seed-support"]
|
||||
|
||||
[dependencies]
|
||||
audio = { path = "../audio" }
|
||||
collections = { path = "../collections" }
|
||||
live_kit_server = { path = "../live_kit_server" }
|
||||
rpc = { path = "../rpc" }
|
||||
|
|
|
@ -203,6 +203,7 @@ impl TestServer {
|
|||
language::init(cx);
|
||||
editor::init_settings(cx);
|
||||
workspace::init(app_state.clone(), cx);
|
||||
audio::init((), cx);
|
||||
call::init(client.clone(), user_store.clone(), cx);
|
||||
});
|
||||
|
||||
|
|
|
@ -388,6 +388,7 @@ struct FakeFsState {
|
|||
event_txs: Vec<smol::channel::Sender<Vec<fsevent::Event>>>,
|
||||
events_paused: bool,
|
||||
buffered_events: Vec<fsevent::Event>,
|
||||
metadata_call_count: usize,
|
||||
read_dir_call_count: usize,
|
||||
}
|
||||
|
||||
|
@ -538,6 +539,7 @@ impl FakeFs {
|
|||
buffered_events: Vec::new(),
|
||||
events_paused: false,
|
||||
read_dir_call_count: 0,
|
||||
metadata_call_count: 0,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
@ -774,10 +776,16 @@ impl FakeFs {
|
|||
result
|
||||
}
|
||||
|
||||
/// How many `read_dir` calls have been issued.
|
||||
pub fn read_dir_call_count(&self) -> usize {
|
||||
self.state.lock().read_dir_call_count
|
||||
}
|
||||
|
||||
/// How many `metadata` calls have been issued.
|
||||
pub fn metadata_call_count(&self) -> usize {
|
||||
self.state.lock().metadata_call_count
|
||||
}
|
||||
|
||||
async fn simulate_random_delay(&self) {
|
||||
self.executor
|
||||
.upgrade()
|
||||
|
@ -1098,7 +1106,8 @@ impl Fs for FakeFs {
|
|||
async fn metadata(&self, path: &Path) -> Result<Option<Metadata>> {
|
||||
self.simulate_random_delay().await;
|
||||
let path = normalize_path(path);
|
||||
let state = self.state.lock();
|
||||
let mut state = self.state.lock();
|
||||
state.metadata_call_count += 1;
|
||||
if let Some((mut entry, _)) = state.try_read_path(&path, false) {
|
||||
let is_symlink = entry.lock().is_symlink();
|
||||
if is_symlink {
|
||||
|
|
|
@ -596,6 +596,8 @@ async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppCon
|
|||
);
|
||||
});
|
||||
|
||||
let prev_read_dir_count = fs.read_dir_call_count();
|
||||
|
||||
// Keep track of the FS events reported to the language server.
|
||||
let fake_server = fake_servers.next().await.unwrap();
|
||||
let file_changes = Arc::new(Mutex::new(Vec::new()));
|
||||
|
@ -607,6 +609,12 @@ async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppCon
|
|||
register_options: serde_json::to_value(
|
||||
lsp::DidChangeWatchedFilesRegistrationOptions {
|
||||
watchers: vec![
|
||||
lsp::FileSystemWatcher {
|
||||
glob_pattern: lsp::GlobPattern::String(
|
||||
"/the-root/Cargo.toml".to_string(),
|
||||
),
|
||||
kind: None,
|
||||
},
|
||||
lsp::FileSystemWatcher {
|
||||
glob_pattern: lsp::GlobPattern::String(
|
||||
"/the-root/src/*.{rs,c}".to_string(),
|
||||
|
@ -638,6 +646,7 @@ async fn test_reporting_fs_changes_to_language_servers(cx: &mut gpui::TestAppCon
|
|||
|
||||
cx.foreground().run_until_parked();
|
||||
assert_eq!(mem::take(&mut *file_changes.lock()), &[]);
|
||||
assert_eq!(fs.read_dir_call_count() - prev_read_dir_count, 4);
|
||||
|
||||
// Now the language server has asked us to watch an ignored directory path,
|
||||
// so we recursively load it.
|
||||
|
|
|
@ -2140,6 +2140,7 @@ impl LocalSnapshot {
|
|||
impl BackgroundScannerState {
|
||||
fn should_scan_directory(&self, entry: &Entry) -> bool {
|
||||
(!entry.is_external && !entry.is_ignored)
|
||||
|| entry.path.file_name() == Some(&*DOT_GIT)
|
||||
|| self.scanned_dirs.contains(&entry.id) // If we've ever scanned it, keep scanning
|
||||
|| self
|
||||
.paths_to_scan
|
||||
|
@ -2319,6 +2320,7 @@ impl BackgroundScannerState {
|
|||
.entry_for_id(entry_id)
|
||||
.map(|entry| RepositoryWorkDirectory(entry.path.clone())) else { continue };
|
||||
|
||||
log::info!("reload git repository {:?}", dot_git_dir);
|
||||
let repository = repository.repo_ptr.lock();
|
||||
let branch = repository.branch_name();
|
||||
repository.reload_index();
|
||||
|
@ -2359,6 +2361,8 @@ impl BackgroundScannerState {
|
|||
}
|
||||
|
||||
fn build_repository(&mut self, dot_git_path: Arc<Path>, fs: &dyn Fs) -> Option<()> {
|
||||
log::info!("build git repository {:?}", dot_git_path);
|
||||
|
||||
let work_dir_path: Arc<Path> = dot_git_path.parent().unwrap().into();
|
||||
|
||||
// Guard against repositories inside the repository metadata
|
||||
|
@ -3071,17 +3075,20 @@ impl BackgroundScanner {
|
|||
|
||||
path_prefix = self.path_prefixes_to_scan_rx.recv().fuse() => {
|
||||
let Ok(path_prefix) = path_prefix else { break };
|
||||
log::trace!("adding path prefix {:?}", path_prefix);
|
||||
|
||||
self.forcibly_load_paths(&[path_prefix.clone()]).await;
|
||||
let did_scan = self.forcibly_load_paths(&[path_prefix.clone()]).await;
|
||||
if did_scan {
|
||||
let abs_path =
|
||||
{
|
||||
let mut state = self.state.lock();
|
||||
state.path_prefixes_to_scan.insert(path_prefix.clone());
|
||||
state.snapshot.abs_path.join(&path_prefix)
|
||||
};
|
||||
|
||||
let abs_path =
|
||||
{
|
||||
let mut state = self.state.lock();
|
||||
state.path_prefixes_to_scan.insert(path_prefix.clone());
|
||||
state.snapshot.abs_path.join(path_prefix)
|
||||
};
|
||||
if let Some(abs_path) = self.fs.canonicalize(&abs_path).await.log_err() {
|
||||
self.process_events(vec![abs_path]).await;
|
||||
if let Some(abs_path) = self.fs.canonicalize(&abs_path).await.log_err() {
|
||||
self.process_events(vec![abs_path]).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3097,10 +3104,13 @@ impl BackgroundScanner {
|
|||
}
|
||||
}
|
||||
|
||||
async fn process_scan_request(&self, request: ScanRequest, scanning: bool) -> bool {
|
||||
async fn process_scan_request(&self, mut request: ScanRequest, scanning: bool) -> bool {
|
||||
log::debug!("rescanning paths {:?}", request.relative_paths);
|
||||
|
||||
let root_path = self.forcibly_load_paths(&request.relative_paths).await;
|
||||
request.relative_paths.sort_unstable();
|
||||
self.forcibly_load_paths(&request.relative_paths).await;
|
||||
|
||||
let root_path = self.state.lock().snapshot.abs_path.clone();
|
||||
let root_canonical_path = match self.fs.canonicalize(&root_path).await {
|
||||
Ok(path) => path,
|
||||
Err(err) => {
|
||||
|
@ -3108,10 +3118,9 @@ impl BackgroundScanner {
|
|||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
let abs_paths = request
|
||||
.relative_paths
|
||||
.into_iter()
|
||||
.iter()
|
||||
.map(|path| {
|
||||
if path.file_name().is_some() {
|
||||
root_canonical_path.join(path)
|
||||
|
@ -3120,14 +3129,19 @@ impl BackgroundScanner {
|
|||
}
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
self.reload_entries_for_paths(root_path, root_canonical_path, abs_paths, None)
|
||||
.await;
|
||||
|
||||
self.reload_entries_for_paths(
|
||||
root_path,
|
||||
root_canonical_path,
|
||||
&request.relative_paths,
|
||||
abs_paths,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
self.send_status_update(scanning, Some(request.done))
|
||||
}
|
||||
|
||||
async fn process_events(&mut self, abs_paths: Vec<PathBuf>) {
|
||||
log::debug!("received fs events {:?}", abs_paths);
|
||||
|
||||
async fn process_events(&mut self, mut abs_paths: Vec<PathBuf>) {
|
||||
let root_path = self.state.lock().snapshot.abs_path.clone();
|
||||
let root_canonical_path = match self.fs.canonicalize(&root_path).await {
|
||||
Ok(path) => path,
|
||||
|
@ -3137,15 +3151,52 @@ impl BackgroundScanner {
|
|||
}
|
||||
};
|
||||
|
||||
let mut relative_paths = Vec::with_capacity(abs_paths.len());
|
||||
abs_paths.sort_unstable();
|
||||
abs_paths.dedup_by(|a, b| a.starts_with(&b));
|
||||
abs_paths.retain(|abs_path| {
|
||||
let snapshot = &self.state.lock().snapshot;
|
||||
{
|
||||
let relative_path: Arc<Path> =
|
||||
if let Ok(path) = abs_path.strip_prefix(&root_canonical_path) {
|
||||
path.into()
|
||||
} else {
|
||||
log::error!(
|
||||
"ignoring event {abs_path:?} outside of root path {root_canonical_path:?}",
|
||||
);
|
||||
return false;
|
||||
};
|
||||
|
||||
let parent_dir_is_loaded = relative_path.parent().map_or(true, |parent| {
|
||||
snapshot
|
||||
.entry_for_path(parent)
|
||||
.map_or(false, |entry| entry.kind == EntryKind::Dir)
|
||||
});
|
||||
if !parent_dir_is_loaded {
|
||||
log::debug!("ignoring event {relative_path:?} within unloaded directory");
|
||||
return false;
|
||||
}
|
||||
|
||||
relative_paths.push(relative_path);
|
||||
true
|
||||
}
|
||||
});
|
||||
|
||||
if relative_paths.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
log::debug!("received fs events {:?}", relative_paths);
|
||||
|
||||
let (scan_job_tx, scan_job_rx) = channel::unbounded();
|
||||
let paths = self
|
||||
.reload_entries_for_paths(
|
||||
root_path,
|
||||
root_canonical_path,
|
||||
abs_paths,
|
||||
Some(scan_job_tx.clone()),
|
||||
)
|
||||
.await;
|
||||
self.reload_entries_for_paths(
|
||||
root_path,
|
||||
root_canonical_path,
|
||||
&relative_paths,
|
||||
abs_paths,
|
||||
Some(scan_job_tx.clone()),
|
||||
)
|
||||
.await;
|
||||
drop(scan_job_tx);
|
||||
self.scan_dirs(false, scan_job_rx).await;
|
||||
|
||||
|
@ -3155,7 +3206,7 @@ impl BackgroundScanner {
|
|||
|
||||
{
|
||||
let mut state = self.state.lock();
|
||||
state.reload_repositories(&paths, self.fs.as_ref());
|
||||
state.reload_repositories(&relative_paths, self.fs.as_ref());
|
||||
state.snapshot.completed_scan_id = state.snapshot.scan_id;
|
||||
for (_, entry_id) in mem::take(&mut state.removed_entry_ids) {
|
||||
state.scanned_dirs.remove(&entry_id);
|
||||
|
@ -3165,12 +3216,11 @@ impl BackgroundScanner {
|
|||
self.send_status_update(false, None);
|
||||
}
|
||||
|
||||
async fn forcibly_load_paths(&self, paths: &[Arc<Path>]) -> Arc<Path> {
|
||||
let root_path;
|
||||
async fn forcibly_load_paths(&self, paths: &[Arc<Path>]) -> bool {
|
||||
let (scan_job_tx, mut scan_job_rx) = channel::unbounded();
|
||||
{
|
||||
let mut state = self.state.lock();
|
||||
root_path = state.snapshot.abs_path.clone();
|
||||
let root_path = state.snapshot.abs_path.clone();
|
||||
for path in paths {
|
||||
for ancestor in path.ancestors() {
|
||||
if let Some(entry) = state.snapshot.entry_for_path(ancestor) {
|
||||
|
@ -3201,8 +3251,8 @@ impl BackgroundScanner {
|
|||
while let Some(job) = scan_job_rx.next().await {
|
||||
self.scan_dir(&job).await.log_err();
|
||||
}
|
||||
self.state.lock().paths_to_scan.clear();
|
||||
root_path
|
||||
|
||||
mem::take(&mut self.state.lock().paths_to_scan).len() > 0
|
||||
}
|
||||
|
||||
async fn scan_dirs(
|
||||
|
@ -3475,7 +3525,7 @@ impl BackgroundScanner {
|
|||
.expect("channel is unbounded");
|
||||
}
|
||||
} else {
|
||||
log::debug!("defer scanning directory {:?} {:?}", entry.path, entry.kind);
|
||||
log::debug!("defer scanning directory {:?}", entry.path);
|
||||
entry.kind = EntryKind::UnloadedDir;
|
||||
}
|
||||
}
|
||||
|
@ -3490,26 +3540,10 @@ impl BackgroundScanner {
|
|||
&self,
|
||||
root_abs_path: Arc<Path>,
|
||||
root_canonical_path: PathBuf,
|
||||
mut abs_paths: Vec<PathBuf>,
|
||||
relative_paths: &[Arc<Path>],
|
||||
abs_paths: Vec<PathBuf>,
|
||||
scan_queue_tx: Option<Sender<ScanJob>>,
|
||||
) -> Vec<Arc<Path>> {
|
||||
let mut event_paths = Vec::<Arc<Path>>::with_capacity(abs_paths.len());
|
||||
abs_paths.sort_unstable();
|
||||
abs_paths.dedup_by(|a, b| a.starts_with(&b));
|
||||
abs_paths.retain(|abs_path| {
|
||||
if let Ok(path) = abs_path.strip_prefix(&root_canonical_path) {
|
||||
event_paths.push(path.into());
|
||||
true
|
||||
} else {
|
||||
log::error!(
|
||||
"unexpected event {:?} for root path {:?}",
|
||||
abs_path,
|
||||
root_canonical_path
|
||||
);
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
) {
|
||||
let metadata = futures::future::join_all(
|
||||
abs_paths
|
||||
.iter()
|
||||
|
@ -3538,30 +3572,15 @@ impl BackgroundScanner {
|
|||
// Remove any entries for paths that no longer exist or are being recursively
|
||||
// refreshed. Do this before adding any new entries, so that renames can be
|
||||
// detected regardless of the order of the paths.
|
||||
for (path, metadata) in event_paths.iter().zip(metadata.iter()) {
|
||||
for (path, metadata) in relative_paths.iter().zip(metadata.iter()) {
|
||||
if matches!(metadata, Ok(None)) || doing_recursive_update {
|
||||
log::trace!("remove path {:?}", path);
|
||||
state.remove_path(path);
|
||||
}
|
||||
}
|
||||
|
||||
for (path, metadata) in event_paths.iter().zip(metadata.iter()) {
|
||||
if let (Some(parent), true) = (path.parent(), doing_recursive_update) {
|
||||
if state
|
||||
.snapshot
|
||||
.entry_for_path(parent)
|
||||
.map_or(true, |entry| entry.kind != EntryKind::Dir)
|
||||
{
|
||||
log::debug!(
|
||||
"ignoring event {path:?} within unloaded directory {:?}",
|
||||
parent
|
||||
);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
for (path, metadata) in relative_paths.iter().zip(metadata.iter()) {
|
||||
let abs_path: Arc<Path> = root_abs_path.join(&path).into();
|
||||
|
||||
match metadata {
|
||||
Ok(Some((metadata, canonical_path))) => {
|
||||
let ignore_stack = state
|
||||
|
@ -3594,23 +3613,28 @@ impl BackgroundScanner {
|
|||
}
|
||||
}
|
||||
|
||||
let fs_entry = state.insert_entry(fs_entry, self.fs.as_ref());
|
||||
|
||||
if let Some(scan_queue_tx) = &scan_queue_tx {
|
||||
let mut ancestor_inodes = state.snapshot.ancestor_inodes_for_path(&path);
|
||||
if metadata.is_dir && !ancestor_inodes.contains(&metadata.inode) {
|
||||
ancestor_inodes.insert(metadata.inode);
|
||||
smol::block_on(scan_queue_tx.send(ScanJob {
|
||||
abs_path,
|
||||
path: path.clone(),
|
||||
ignore_stack,
|
||||
ancestor_inodes,
|
||||
is_external: fs_entry.is_external,
|
||||
scan_queue: scan_queue_tx.clone(),
|
||||
}))
|
||||
.unwrap();
|
||||
if let (Some(scan_queue_tx), true) = (&scan_queue_tx, fs_entry.is_dir()) {
|
||||
if state.should_scan_directory(&fs_entry) {
|
||||
let mut ancestor_inodes =
|
||||
state.snapshot.ancestor_inodes_for_path(&path);
|
||||
if !ancestor_inodes.contains(&metadata.inode) {
|
||||
ancestor_inodes.insert(metadata.inode);
|
||||
smol::block_on(scan_queue_tx.send(ScanJob {
|
||||
abs_path,
|
||||
path: path.clone(),
|
||||
ignore_stack,
|
||||
ancestor_inodes,
|
||||
is_external: fs_entry.is_external,
|
||||
scan_queue: scan_queue_tx.clone(),
|
||||
}))
|
||||
.unwrap();
|
||||
}
|
||||
} else {
|
||||
fs_entry.kind = EntryKind::UnloadedDir;
|
||||
}
|
||||
}
|
||||
|
||||
state.insert_entry(fs_entry, self.fs.as_ref());
|
||||
}
|
||||
Ok(None) => {
|
||||
self.remove_repo_path(&path, &mut state.snapshot);
|
||||
|
@ -3624,12 +3648,10 @@ impl BackgroundScanner {
|
|||
|
||||
util::extend_sorted(
|
||||
&mut state.changed_paths,
|
||||
event_paths.iter().cloned(),
|
||||
relative_paths.iter().cloned(),
|
||||
usize::MAX,
|
||||
Ord::cmp,
|
||||
);
|
||||
|
||||
event_paths
|
||||
}
|
||||
|
||||
fn remove_repo_path(&self, path: &Path, snapshot: &mut LocalSnapshot) -> Option<()> {
|
||||
|
@ -3760,25 +3782,22 @@ impl BackgroundScanner {
|
|||
|
||||
// Scan any directories that were previously ignored and weren't
|
||||
// previously scanned.
|
||||
if was_ignored
|
||||
&& !entry.is_ignored
|
||||
&& !entry.is_external
|
||||
&& entry.kind == EntryKind::UnloadedDir
|
||||
{
|
||||
job.scan_queue
|
||||
.try_send(ScanJob {
|
||||
abs_path: abs_path.clone(),
|
||||
path: entry.path.clone(),
|
||||
ignore_stack: child_ignore_stack.clone(),
|
||||
scan_queue: job.scan_queue.clone(),
|
||||
ancestor_inodes: self
|
||||
.state
|
||||
.lock()
|
||||
.snapshot
|
||||
.ancestor_inodes_for_path(&entry.path),
|
||||
is_external: false,
|
||||
})
|
||||
.unwrap();
|
||||
if was_ignored && !entry.is_ignored && entry.kind.is_unloaded() {
|
||||
let state = self.state.lock();
|
||||
if state.should_scan_directory(&entry) {
|
||||
job.scan_queue
|
||||
.try_send(ScanJob {
|
||||
abs_path: abs_path.clone(),
|
||||
path: entry.path.clone(),
|
||||
ignore_stack: child_ignore_stack.clone(),
|
||||
scan_queue: job.scan_queue.clone(),
|
||||
ancestor_inodes: state
|
||||
.snapshot
|
||||
.ancestor_inodes_for_path(&entry.path),
|
||||
is_external: false,
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
job.ignore_queue
|
||||
|
|
|
@ -454,6 +454,10 @@ async fn test_open_gitignored_files(cx: &mut TestAppContext) {
|
|||
"b1.js": "b1",
|
||||
"b2.js": "b2",
|
||||
},
|
||||
"c": {
|
||||
"c1.js": "c1",
|
||||
"c2.js": "c2",
|
||||
}
|
||||
},
|
||||
},
|
||||
"two": {
|
||||
|
@ -521,6 +525,7 @@ async fn test_open_gitignored_files(cx: &mut TestAppContext) {
|
|||
(Path::new("one/node_modules/b"), true),
|
||||
(Path::new("one/node_modules/b/b1.js"), true),
|
||||
(Path::new("one/node_modules/b/b2.js"), true),
|
||||
(Path::new("one/node_modules/c"), true),
|
||||
(Path::new("two"), false),
|
||||
(Path::new("two/x.js"), false),
|
||||
(Path::new("two/y.js"), false),
|
||||
|
@ -564,6 +569,7 @@ async fn test_open_gitignored_files(cx: &mut TestAppContext) {
|
|||
(Path::new("one/node_modules/b"), true),
|
||||
(Path::new("one/node_modules/b/b1.js"), true),
|
||||
(Path::new("one/node_modules/b/b2.js"), true),
|
||||
(Path::new("one/node_modules/c"), true),
|
||||
(Path::new("two"), false),
|
||||
(Path::new("two/x.js"), false),
|
||||
(Path::new("two/y.js"), false),
|
||||
|
@ -578,6 +584,17 @@ async fn test_open_gitignored_files(cx: &mut TestAppContext) {
|
|||
// Only the newly-expanded directory is scanned.
|
||||
assert_eq!(fs.read_dir_call_count() - prev_read_dir_count, 1);
|
||||
});
|
||||
|
||||
// No work happens when files and directories change within an unloaded directory.
|
||||
let prev_fs_call_count = fs.read_dir_call_count() + fs.metadata_call_count();
|
||||
fs.create_dir("/root/one/node_modules/c/lib".as_ref())
|
||||
.await
|
||||
.unwrap();
|
||||
cx.foreground().run_until_parked();
|
||||
assert_eq!(
|
||||
fs.read_dir_call_count() + fs.metadata_call_count() - prev_fs_call_count,
|
||||
0
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
|
@ -1637,6 +1654,23 @@ async fn test_git_status(deterministic: Arc<Deterministic>, cx: &mut TestAppCont
|
|||
|
||||
}));
|
||||
|
||||
const A_TXT: &'static str = "a.txt";
|
||||
const B_TXT: &'static str = "b.txt";
|
||||
const E_TXT: &'static str = "c/d/e.txt";
|
||||
const F_TXT: &'static str = "f.txt";
|
||||
const DOTGITIGNORE: &'static str = ".gitignore";
|
||||
const BUILD_FILE: &'static str = "target/build_file";
|
||||
let project_path = Path::new("project");
|
||||
|
||||
// Set up git repository before creating the worktree.
|
||||
let work_dir = root.path().join("project");
|
||||
let mut repo = git_init(work_dir.as_path());
|
||||
repo.add_ignore_rule(IGNORE_RULE).unwrap();
|
||||
git_add(A_TXT, &repo);
|
||||
git_add(E_TXT, &repo);
|
||||
git_add(DOTGITIGNORE, &repo);
|
||||
git_commit("Initial commit", &repo);
|
||||
|
||||
let tree = Worktree::local(
|
||||
build_client(cx),
|
||||
root.path(),
|
||||
|
@ -1648,26 +1682,9 @@ async fn test_git_status(deterministic: Arc<Deterministic>, cx: &mut TestAppCont
|
|||
.await
|
||||
.unwrap();
|
||||
|
||||
tree.flush_fs_events(cx).await;
|
||||
cx.read(|cx| tree.read(cx).as_local().unwrap().scan_complete())
|
||||
.await;
|
||||
|
||||
const A_TXT: &'static str = "a.txt";
|
||||
const B_TXT: &'static str = "b.txt";
|
||||
const E_TXT: &'static str = "c/d/e.txt";
|
||||
const F_TXT: &'static str = "f.txt";
|
||||
const DOTGITIGNORE: &'static str = ".gitignore";
|
||||
const BUILD_FILE: &'static str = "target/build_file";
|
||||
let project_path: &Path = &Path::new("project");
|
||||
|
||||
let work_dir = root.path().join("project");
|
||||
let mut repo = git_init(work_dir.as_path());
|
||||
repo.add_ignore_rule(IGNORE_RULE).unwrap();
|
||||
git_add(Path::new(A_TXT), &repo);
|
||||
git_add(Path::new(E_TXT), &repo);
|
||||
git_add(Path::new(DOTGITIGNORE), &repo);
|
||||
git_commit("Initial commit", &repo);
|
||||
|
||||
tree.flush_fs_events(cx).await;
|
||||
deterministic.run_until_parked();
|
||||
|
||||
// Check that the right git state is observed on startup
|
||||
|
@ -1687,39 +1704,39 @@ async fn test_git_status(deterministic: Arc<Deterministic>, cx: &mut TestAppCont
|
|||
);
|
||||
});
|
||||
|
||||
// Modify a file in the working copy.
|
||||
std::fs::write(work_dir.join(A_TXT), "aa").unwrap();
|
||||
|
||||
tree.flush_fs_events(cx).await;
|
||||
deterministic.run_until_parked();
|
||||
|
||||
// The worktree detects that the file's git status has changed.
|
||||
tree.read_with(cx, |tree, _cx| {
|
||||
let snapshot = tree.snapshot();
|
||||
|
||||
assert_eq!(
|
||||
snapshot.status_for_file(project_path.join(A_TXT)),
|
||||
Some(GitFileStatus::Modified)
|
||||
);
|
||||
});
|
||||
|
||||
git_add(Path::new(A_TXT), &repo);
|
||||
git_add(Path::new(B_TXT), &repo);
|
||||
// Create a commit in the git repository.
|
||||
git_add(A_TXT, &repo);
|
||||
git_add(B_TXT, &repo);
|
||||
git_commit("Committing modified and added", &repo);
|
||||
tree.flush_fs_events(cx).await;
|
||||
deterministic.run_until_parked();
|
||||
|
||||
// Check that repo only changes are tracked
|
||||
// The worktree detects that the files' git status have changed.
|
||||
tree.read_with(cx, |tree, _cx| {
|
||||
let snapshot = tree.snapshot();
|
||||
|
||||
assert_eq!(
|
||||
snapshot.status_for_file(project_path.join(F_TXT)),
|
||||
Some(GitFileStatus::Added)
|
||||
);
|
||||
|
||||
assert_eq!(snapshot.status_for_file(project_path.join(B_TXT)), None);
|
||||
assert_eq!(snapshot.status_for_file(project_path.join(A_TXT)), None);
|
||||
});
|
||||
|
||||
// Modify files in the working copy and perform git operations on other files.
|
||||
git_reset(0, &repo);
|
||||
git_remove_index(Path::new(B_TXT), &repo);
|
||||
git_stash(&mut repo);
|
||||
|
|
|
@ -3,7 +3,7 @@ authors = ["Nathan Sobo <nathansobo@gmail.com>"]
|
|||
description = "The fast, collaborative code editor."
|
||||
edition = "2021"
|
||||
name = "zed"
|
||||
version = "0.93.0"
|
||||
version = "0.93.4"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
|
@ -16,6 +16,7 @@ name = "Zed"
|
|||
path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
audio = { path = "../audio" }
|
||||
activity_indicator = { path = "../activity_indicator" }
|
||||
auto_update = { path = "../auto_update" }
|
||||
breadcrumbs = { path = "../breadcrumbs" }
|
||||
|
|
|
@ -1 +1 @@
|
|||
dev
|
||||
stable
|
|
@ -7,6 +7,7 @@ use rust_embed::RustEmbed;
|
|||
#[include = "fonts/**/*"]
|
||||
#[include = "icons/**/*"]
|
||||
#[include = "themes/**/*"]
|
||||
#[include = "sounds/**/*"]
|
||||
#[include = "*.md"]
|
||||
#[exclude = "*.DS_Store"]
|
||||
pub struct Assets;
|
||||
|
|
|
@ -180,6 +180,8 @@ fn main() {
|
|||
background_actions,
|
||||
});
|
||||
cx.set_global(Arc::downgrade(&app_state));
|
||||
|
||||
audio::init(Assets, cx);
|
||||
auto_update::init(http.clone(), client::ZED_SERVER_URL.clone(), cx);
|
||||
|
||||
workspace::init(app_state.clone(), cx);
|
||||
|
|
|
@ -2160,6 +2160,7 @@ mod tests {
|
|||
state.initialize_workspace = initialize_workspace;
|
||||
state.build_window_options = build_window_options;
|
||||
theme::init((), cx);
|
||||
audio::init((), cx);
|
||||
call::init(app_state.client.clone(), app_state.user_store.clone(), cx);
|
||||
workspace::init(app_state.clone(), cx);
|
||||
Project::init_settings(cx);
|
||||
|
|
|
@ -1,25 +1,32 @@
|
|||
import { ColorScheme } from "../common";
|
||||
import { interactive, toggleable } from "../element";
|
||||
import { background, foreground } from "../styleTree/components";
|
||||
import { ColorScheme } from "../common"
|
||||
import { interactive, toggleable } from "../element"
|
||||
import { background, foreground } from "../styleTree/components"
|
||||
|
||||
export type Margin = {
|
||||
top: number;
|
||||
bottom: number;
|
||||
left: number;
|
||||
right: number;
|
||||
top: number
|
||||
bottom: number
|
||||
left: number
|
||||
right: number
|
||||
}
|
||||
|
||||
interface IconButtonOptions {
|
||||
layer?: ColorScheme['lowest'] | ColorScheme['middle'] | ColorScheme['highest'];
|
||||
color?: keyof ColorScheme['lowest'];
|
||||
margin?: Partial<Margin>;
|
||||
layer?:
|
||||
| ColorScheme["lowest"]
|
||||
| ColorScheme["middle"]
|
||||
| ColorScheme["highest"]
|
||||
color?: keyof ColorScheme["lowest"]
|
||||
margin?: Partial<Margin>
|
||||
}
|
||||
|
||||
type ToggleableIconButtonOptions = IconButtonOptions & { active_color?: keyof ColorScheme['lowest'] };
|
||||
type ToggleableIconButtonOptions = IconButtonOptions & {
|
||||
active_color?: keyof ColorScheme["lowest"]
|
||||
}
|
||||
|
||||
export function icon_button(theme: ColorScheme, { color, margin, layer }: IconButtonOptions) {
|
||||
if (!color)
|
||||
color = "base";
|
||||
export function icon_button(
|
||||
theme: ColorScheme,
|
||||
{ color, margin, layer }: IconButtonOptions
|
||||
) {
|
||||
if (!color) color = "base"
|
||||
|
||||
const m = {
|
||||
top: margin?.top ?? 0,
|
||||
|
@ -51,25 +58,29 @@ export function icon_button(theme: ColorScheme, { color, margin, layer }: IconBu
|
|||
hovered: {
|
||||
background: background(layer ?? theme.lowest, color, "hovered"),
|
||||
color: foreground(layer ?? theme.lowest, color, "hovered"),
|
||||
|
||||
},
|
||||
clicked: {
|
||||
background: background(layer ?? theme.lowest, color, "pressed"),
|
||||
color: foreground(layer ?? theme.lowest, color, "pressed"),
|
||||
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
export function toggleable_icon_button(theme: ColorScheme, { color, active_color, margin }: ToggleableIconButtonOptions) {
|
||||
if (!color)
|
||||
color = "base";
|
||||
export function toggleable_icon_button(
|
||||
theme: ColorScheme,
|
||||
{ color, active_color, margin }: ToggleableIconButtonOptions
|
||||
) {
|
||||
if (!color) color = "base"
|
||||
|
||||
return toggleable({
|
||||
state: {
|
||||
inactive: icon_button(theme, { color, margin }),
|
||||
active: icon_button(theme, { color: active_color ? active_color : color, margin, layer: theme.middle }),
|
||||
}
|
||||
active: icon_button(theme, {
|
||||
color: active_color ? active_color : color,
|
||||
margin,
|
||||
layer: theme.middle,
|
||||
}),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,25 +1,37 @@
|
|||
import { ColorScheme } from "../common";
|
||||
import { interactive, toggleable } from "../element";
|
||||
import { TextProperties, background, foreground, text } from "../styleTree/components";
|
||||
import { Margin } from "./icon_button";
|
||||
import { ColorScheme } from "../common"
|
||||
import { interactive, toggleable } from "../element"
|
||||
import {
|
||||
TextProperties,
|
||||
background,
|
||||
foreground,
|
||||
text,
|
||||
} from "../styleTree/components"
|
||||
import { Margin } from "./icon_button"
|
||||
|
||||
interface TextButtonOptions {
|
||||
layer?: ColorScheme['lowest'] | ColorScheme['middle'] | ColorScheme['highest'];
|
||||
color?: keyof ColorScheme['lowest'];
|
||||
margin?: Partial<Margin>;
|
||||
text_properties?: TextProperties;
|
||||
layer?:
|
||||
| ColorScheme["lowest"]
|
||||
| ColorScheme["middle"]
|
||||
| ColorScheme["highest"]
|
||||
color?: keyof ColorScheme["lowest"]
|
||||
margin?: Partial<Margin>
|
||||
text_properties?: TextProperties
|
||||
}
|
||||
|
||||
type ToggleableTextButtonOptions = TextButtonOptions & { active_color?: keyof ColorScheme['lowest'] };
|
||||
type ToggleableTextButtonOptions = TextButtonOptions & {
|
||||
active_color?: keyof ColorScheme["lowest"]
|
||||
}
|
||||
|
||||
export function text_button(theme: ColorScheme, { color, layer, margin, text_properties }: TextButtonOptions) {
|
||||
if (!color)
|
||||
color = "base";
|
||||
export function text_button(
|
||||
theme: ColorScheme,
|
||||
{ color, layer, margin, text_properties }: TextButtonOptions
|
||||
) {
|
||||
if (!color) color = "base"
|
||||
|
||||
const text_options: TextProperties = {
|
||||
size: "xs",
|
||||
weight: "normal",
|
||||
...text_properties
|
||||
...text_properties,
|
||||
}
|
||||
|
||||
const m = {
|
||||
|
@ -40,7 +52,7 @@ export function text_button(theme: ColorScheme, { color, layer, margin, text_pro
|
|||
},
|
||||
margin: m,
|
||||
button_height: 22,
|
||||
...text(layer ?? theme.lowest, "sans", color, text_options)
|
||||
...text(layer ?? theme.lowest, "sans", color, text_options),
|
||||
},
|
||||
state: {
|
||||
default: {
|
||||
|
@ -50,25 +62,29 @@ export function text_button(theme: ColorScheme, { color, layer, margin, text_pro
|
|||
hovered: {
|
||||
background: background(layer ?? theme.lowest, color, "hovered"),
|
||||
color: foreground(layer ?? theme.lowest, color, "hovered"),
|
||||
|
||||
},
|
||||
clicked: {
|
||||
background: background(layer ?? theme.lowest, color, "pressed"),
|
||||
color: foreground(layer ?? theme.lowest, color, "pressed"),
|
||||
|
||||
},
|
||||
},
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
export function toggleable_text_button(theme: ColorScheme, { color, active_color, margin }: ToggleableTextButtonOptions) {
|
||||
if (!color)
|
||||
color = "base";
|
||||
export function toggleable_text_button(
|
||||
theme: ColorScheme,
|
||||
{ color, active_color, margin }: ToggleableTextButtonOptions
|
||||
) {
|
||||
if (!color) color = "base"
|
||||
|
||||
return toggleable({
|
||||
state: {
|
||||
inactive: text_button(theme, { color, margin }),
|
||||
active: text_button(theme, { color: active_color ? active_color : color, margin, layer: theme.middle }),
|
||||
}
|
||||
active: text_button(theme, {
|
||||
color: active_color ? active_color : color,
|
||||
margin,
|
||||
layer: theme.middle,
|
||||
}),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import merge from "ts-deepmerge"
|
||||
import { DeepPartial } from "utility-types"
|
||||
|
||||
type InteractiveState =
|
||||
export type InteractiveState =
|
||||
| "default"
|
||||
| "hovered"
|
||||
| "clicked"
|
||||
|
|
|
@ -26,15 +26,15 @@ export default function assistant(colorScheme: ColorScheme) {
|
|||
},
|
||||
container: {
|
||||
padding: { left: 12, right: 8.5 },
|
||||
}
|
||||
},
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
icon: {
|
||||
color: foreground(layer, "hovered")
|
||||
}
|
||||
}
|
||||
}
|
||||
color: foreground(layer, "hovered"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
splitButton: interactive({
|
||||
base: {
|
||||
|
@ -48,15 +48,15 @@ export default function assistant(colorScheme: ColorScheme) {
|
|||
},
|
||||
container: {
|
||||
padding: { left: 8.5, right: 8.5 },
|
||||
}
|
||||
},
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
icon: {
|
||||
color: foreground(layer, "hovered")
|
||||
}
|
||||
}
|
||||
}
|
||||
color: foreground(layer, "hovered"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
quoteButton: interactive({
|
||||
base: {
|
||||
|
@ -70,15 +70,15 @@ export default function assistant(colorScheme: ColorScheme) {
|
|||
},
|
||||
container: {
|
||||
padding: { left: 8.5, right: 8.5 },
|
||||
}
|
||||
},
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
icon: {
|
||||
color: foreground(layer, "hovered")
|
||||
}
|
||||
}
|
||||
}
|
||||
color: foreground(layer, "hovered"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
assistButton: interactive({
|
||||
base: {
|
||||
|
@ -92,15 +92,15 @@ export default function assistant(colorScheme: ColorScheme) {
|
|||
},
|
||||
container: {
|
||||
padding: { left: 8.5, right: 8.5 },
|
||||
}
|
||||
},
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
icon: {
|
||||
color: foreground(layer, "hovered")
|
||||
}
|
||||
}
|
||||
}
|
||||
color: foreground(layer, "hovered"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
zoomInButton: interactive({
|
||||
base: {
|
||||
|
@ -114,15 +114,15 @@ export default function assistant(colorScheme: ColorScheme) {
|
|||
},
|
||||
container: {
|
||||
padding: { left: 10, right: 10 },
|
||||
}
|
||||
},
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
icon: {
|
||||
color: foreground(layer, "hovered")
|
||||
}
|
||||
}
|
||||
}
|
||||
color: foreground(layer, "hovered"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
zoomOutButton: interactive({
|
||||
base: {
|
||||
|
@ -136,15 +136,15 @@ export default function assistant(colorScheme: ColorScheme) {
|
|||
},
|
||||
container: {
|
||||
padding: { left: 10, right: 10 },
|
||||
}
|
||||
},
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
icon: {
|
||||
color: foreground(layer, "hovered")
|
||||
}
|
||||
}
|
||||
}
|
||||
color: foreground(layer, "hovered"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
plusButton: interactive({
|
||||
base: {
|
||||
|
@ -158,29 +158,29 @@ export default function assistant(colorScheme: ColorScheme) {
|
|||
},
|
||||
container: {
|
||||
padding: { left: 10, right: 10 },
|
||||
}
|
||||
},
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
icon: {
|
||||
color: foreground(layer, "hovered")
|
||||
}
|
||||
}
|
||||
}
|
||||
color: foreground(layer, "hovered"),
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
title: {
|
||||
...text(layer, "sans", "default", { size: "sm" })
|
||||
...text(layer, "sans", "default", { size: "sm" }),
|
||||
},
|
||||
savedConversation: {
|
||||
container: interactive({
|
||||
base: {
|
||||
background: background(layer, "on"),
|
||||
padding: { top: 4, bottom: 4 }
|
||||
padding: { top: 4, bottom: 4 },
|
||||
},
|
||||
state: {
|
||||
hovered: {
|
||||
background: background(layer, "on", "hovered"),
|
||||
}
|
||||
},
|
||||
},
|
||||
}),
|
||||
savedAt: {
|
||||
|
@ -189,8 +189,11 @@ export default function assistant(colorScheme: ColorScheme) {
|
|||
},
|
||||
title: {
|
||||
margin: { left: 16 },
|
||||
...text(layer, "sans", "default", { size: "sm", weight: "bold" }),
|
||||
}
|
||||
...text(layer, "sans", "default", {
|
||||
size: "sm",
|
||||
weight: "bold",
|
||||
}),
|
||||
},
|
||||
},
|
||||
userSender: {
|
||||
default: {
|
||||
|
|
|
@ -93,6 +93,14 @@ interface Text extends Object {
|
|||
underline?: boolean
|
||||
}
|
||||
|
||||
export interface TextStyle extends Object {
|
||||
family: keyof typeof fontFamilies
|
||||
color: string
|
||||
size: number
|
||||
weight?: FontWeight
|
||||
underline?: boolean
|
||||
}
|
||||
|
||||
export interface TextProperties {
|
||||
size?: keyof typeof fontSizes
|
||||
weight?: FontWeight
|
||||
|
|
|
@ -1,73 +1,125 @@
|
|||
import { ColorScheme } from "../theme/colorScheme"
|
||||
import { withOpacity } from "../theme/color"
|
||||
import { background, border, foreground, text } from "./components"
|
||||
import {
|
||||
Border,
|
||||
TextStyle,
|
||||
background,
|
||||
border,
|
||||
foreground,
|
||||
text,
|
||||
} from "./components"
|
||||
import { interactive, toggleable } from "../element"
|
||||
import merge from "ts-deepmerge"
|
||||
export default function projectPanel(colorScheme: ColorScheme) {
|
||||
const { isLight } = colorScheme
|
||||
|
||||
let layer = colorScheme.middle
|
||||
|
||||
let baseEntry = {
|
||||
height: 22,
|
||||
iconColor: foreground(layer, "variant"),
|
||||
iconSize: 7,
|
||||
iconSpacing: 5,
|
||||
type EntryStateProps = {
|
||||
background?: string
|
||||
border?: Border
|
||||
text?: TextStyle
|
||||
iconColor?: string
|
||||
}
|
||||
|
||||
let status = {
|
||||
git: {
|
||||
modified: isLight
|
||||
? colorScheme.ramps.yellow(0.6).hex()
|
||||
: colorScheme.ramps.yellow(0.5).hex(),
|
||||
inserted: isLight
|
||||
? colorScheme.ramps.green(0.45).hex()
|
||||
: colorScheme.ramps.green(0.5).hex(),
|
||||
conflict: isLight
|
||||
? colorScheme.ramps.red(0.6).hex()
|
||||
: colorScheme.ramps.red(0.5).hex(),
|
||||
},
|
||||
type EntryState = {
|
||||
default: EntryStateProps
|
||||
hovered?: EntryStateProps
|
||||
clicked?: EntryStateProps
|
||||
}
|
||||
|
||||
const default_entry = interactive({
|
||||
base: {
|
||||
...baseEntry,
|
||||
text: text(layer, "mono", "variant", { size: "sm" }),
|
||||
status,
|
||||
},
|
||||
state: {
|
||||
default: {
|
||||
background: background(layer),
|
||||
const entry = (unselected?: EntryState, selected?: EntryState) => {
|
||||
const git_status = {
|
||||
git: {
|
||||
modified: isLight
|
||||
? colorScheme.ramps.yellow(0.6).hex()
|
||||
: colorScheme.ramps.yellow(0.5).hex(),
|
||||
inserted: isLight
|
||||
? colorScheme.ramps.green(0.45).hex()
|
||||
: colorScheme.ramps.green(0.5).hex(),
|
||||
conflict: isLight
|
||||
? colorScheme.ramps.red(0.6).hex()
|
||||
: colorScheme.ramps.red(0.5).hex(),
|
||||
},
|
||||
hovered: {
|
||||
background: background(layer, "variant", "hovered"),
|
||||
},
|
||||
clicked: {
|
||||
background: background(layer, "variant", "pressed"),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
let entry = toggleable({
|
||||
base: default_entry,
|
||||
state: {
|
||||
active: interactive({
|
||||
base: {
|
||||
...default_entry,
|
||||
},
|
||||
state: {
|
||||
default: {
|
||||
background: background(colorScheme.lowest),
|
||||
const base_properties = {
|
||||
height: 22,
|
||||
background: background(layer),
|
||||
iconColor: foreground(layer, "variant"),
|
||||
iconSize: 7,
|
||||
iconSpacing: 5,
|
||||
text: text(layer, "sans", "variant", { size: "sm" }),
|
||||
status: {
|
||||
...git_status,
|
||||
},
|
||||
}
|
||||
|
||||
const selectedStyle: EntryState | undefined = selected
|
||||
? selected
|
||||
: unselected
|
||||
|
||||
const unselected_default_style = merge(
|
||||
base_properties,
|
||||
unselected?.default ?? {},
|
||||
{}
|
||||
)
|
||||
const unselected_hovered_style = merge(
|
||||
base_properties,
|
||||
{ background: background(layer, "hovered") },
|
||||
unselected?.hovered ?? {},
|
||||
)
|
||||
const unselected_clicked_style = merge(
|
||||
base_properties,
|
||||
{ background: background(layer, "pressed") },
|
||||
unselected?.clicked ?? {},
|
||||
)
|
||||
const selected_default_style = merge(
|
||||
base_properties,
|
||||
{
|
||||
background: background(colorScheme.lowest),
|
||||
text: text(colorScheme.lowest, "sans", { size: "sm" }),
|
||||
},
|
||||
selectedStyle?.default ?? {},
|
||||
)
|
||||
const selected_hovered_style = merge(
|
||||
base_properties,
|
||||
{
|
||||
background: background(colorScheme.lowest, "hovered"),
|
||||
text: text(colorScheme.lowest, "sans", { size: "sm" }),
|
||||
},
|
||||
selectedStyle?.hovered ?? {},
|
||||
)
|
||||
const selected_clicked_style = merge(
|
||||
base_properties,
|
||||
{
|
||||
background: background(colorScheme.lowest, "pressed"),
|
||||
text: text(colorScheme.lowest, "sans", { size: "sm" }),
|
||||
},
|
||||
selectedStyle?.clicked ?? {},
|
||||
)
|
||||
|
||||
return toggleable({
|
||||
state: {
|
||||
inactive: interactive({
|
||||
state: {
|
||||
default: unselected_default_style,
|
||||
hovered: unselected_hovered_style,
|
||||
clicked: unselected_clicked_style,
|
||||
},
|
||||
hovered: {
|
||||
background: background(colorScheme.lowest, "hovered"),
|
||||
}),
|
||||
active: interactive({
|
||||
state: {
|
||||
default: selected_default_style,
|
||||
hovered: selected_hovered_style,
|
||||
clicked: selected_clicked_style,
|
||||
},
|
||||
clicked: {
|
||||
background: background(colorScheme.lowest, "pressed"),
|
||||
},
|
||||
},
|
||||
}),
|
||||
},
|
||||
})
|
||||
}),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
const defaultEntry = entry()
|
||||
|
||||
return {
|
||||
openProjectButton: interactive({
|
||||
|
@ -104,38 +156,41 @@ export default function projectPanel(colorScheme: ColorScheme) {
|
|||
background: background(layer),
|
||||
padding: { left: 6, right: 6, top: 0, bottom: 6 },
|
||||
indentWidth: 12,
|
||||
entry,
|
||||
entry: defaultEntry,
|
||||
draggedEntry: {
|
||||
...baseEntry,
|
||||
text: text(layer, "mono", "on", { size: "sm" }),
|
||||
...defaultEntry.inactive.default,
|
||||
text: text(layer, "sans", "on", { size: "sm" }),
|
||||
background: withOpacity(background(layer, "on"), 0.9),
|
||||
border: border(layer),
|
||||
status,
|
||||
},
|
||||
ignoredEntry: {
|
||||
...entry,
|
||||
iconColor: foreground(layer, "disabled"),
|
||||
text: text(layer, "mono", "disabled"),
|
||||
active: {
|
||||
...entry.active,
|
||||
iconColor: foreground(layer, "variant"),
|
||||
},
|
||||
},
|
||||
cutEntry: {
|
||||
...entry,
|
||||
text: text(layer, "mono", "disabled"),
|
||||
active: {
|
||||
...entry.active,
|
||||
ignoredEntry: entry(
|
||||
{
|
||||
default: {
|
||||
...entry.active.default,
|
||||
background: background(layer, "active"),
|
||||
text: text(layer, "mono", "disabled", { size: "sm" }),
|
||||
text: text(layer, "sans", "disabled"),
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
default: {
|
||||
iconColor: foreground(layer, "variant"),
|
||||
},
|
||||
}
|
||||
),
|
||||
cutEntry: entry(
|
||||
{
|
||||
default: {
|
||||
text: text(layer, "sans", "disabled"),
|
||||
},
|
||||
},
|
||||
{
|
||||
default: {
|
||||
background: background(layer, "active"),
|
||||
text: text(layer, "sans", "disabled", { size: "sm" }),
|
||||
},
|
||||
}
|
||||
),
|
||||
filenameEditor: {
|
||||
background: background(layer, "on"),
|
||||
text: text(layer, "mono", "on", { size: "sm" }),
|
||||
text: text(layer, "sans", "on", { size: "sm" }),
|
||||
selection: colorScheme.players[0],
|
||||
},
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { ColorScheme } from "../common";
|
||||
import { ColorScheme } from "../common"
|
||||
import { icon_button, toggleable_icon_button } from "../component/icon_button"
|
||||
import { toggleable_text_button } from "../component/text_button"
|
||||
import { interactive, toggleable } from "../element"
|
||||
import { withOpacity } from "../theme/color";
|
||||
import { background, border, foreground, text } from "./components";
|
||||
import { withOpacity } from "../theme/color"
|
||||
import { background, border, foreground, text } from "./components"
|
||||
|
||||
const ITEM_SPACING = 8
|
||||
const TITLEBAR_HEIGHT = 32
|
||||
|
@ -25,7 +25,7 @@ function build_spacing(
|
|||
function call_controls(theme: ColorScheme) {
|
||||
const button_height = 18
|
||||
|
||||
const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING);
|
||||
const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING)
|
||||
const marginY = {
|
||||
top: space.marginY,
|
||||
bottom: space.marginY,
|
||||
|
@ -38,14 +38,14 @@ function call_controls(theme: ColorScheme) {
|
|||
left: space.group,
|
||||
right: space.half_item,
|
||||
},
|
||||
active_color: 'negative'
|
||||
active_color: "negative",
|
||||
}),
|
||||
|
||||
toggle_speakers_button: toggleable_icon_button(theme, {
|
||||
margin: {
|
||||
...marginY,
|
||||
left: space.half_item,
|
||||
right: space.half_item
|
||||
right: space.half_item,
|
||||
},
|
||||
}),
|
||||
|
||||
|
@ -53,9 +53,9 @@ function call_controls(theme: ColorScheme) {
|
|||
margin: {
|
||||
...marginY,
|
||||
left: space.half_item,
|
||||
right: space.group
|
||||
right: space.group,
|
||||
},
|
||||
active_color: 'accent'
|
||||
active_color: "accent",
|
||||
}),
|
||||
|
||||
muted: foreground(theme.lowest, "negative"),
|
||||
|
@ -64,15 +64,15 @@ function call_controls(theme: ColorScheme) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Opens the User Menu when toggled
|
||||
*
|
||||
* When logged in shows the user's avatar and a chevron,
|
||||
* When logged out only shows a chevron.
|
||||
*/
|
||||
* Opens the User Menu when toggled
|
||||
*
|
||||
* When logged in shows the user's avatar and a chevron,
|
||||
* When logged out only shows a chevron.
|
||||
*/
|
||||
function user_menu(theme: ColorScheme) {
|
||||
const button_height = 18
|
||||
|
||||
const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING);
|
||||
const space = build_spacing(TITLEBAR_HEIGHT, button_height, ITEM_SPACING)
|
||||
|
||||
const build_button = ({ online }: { online: boolean }) => {
|
||||
const button = toggleable({
|
||||
|
@ -124,8 +124,8 @@ function user_menu(theme: ColorScheme) {
|
|||
background: background(theme.middle, "pressed"),
|
||||
},
|
||||
},
|
||||
}
|
||||
});
|
||||
},
|
||||
})
|
||||
|
||||
return {
|
||||
user_menu: button,
|
||||
|
@ -134,7 +134,7 @@ function user_menu(theme: ColorScheme) {
|
|||
icon_height: 16,
|
||||
corner_radius: 4,
|
||||
outer_width: 16,
|
||||
outer_corner_radius: 16
|
||||
outer_corner_radius: 16,
|
||||
},
|
||||
icon: {
|
||||
margin: {
|
||||
|
@ -145,8 +145,8 @@ function user_menu(theme: ColorScheme) {
|
|||
},
|
||||
width: 11,
|
||||
height: 11,
|
||||
color: foreground(theme.lowest)
|
||||
}
|
||||
color: foreground(theme.lowest),
|
||||
},
|
||||
}
|
||||
}
|
||||
return {
|
||||
|
@ -240,7 +240,7 @@ export function titlebar(theme: ColorScheme) {
|
|||
leave_call_button: icon_button(theme, {
|
||||
margin: {
|
||||
left: ITEM_SPACING / 2,
|
||||
right: ITEM_SPACING
|
||||
right: ITEM_SPACING,
|
||||
},
|
||||
}),
|
||||
|
||||
|
@ -261,6 +261,6 @@ export function titlebar(theme: ColorScheme) {
|
|||
background: foreground(theme.lowest, "accent"),
|
||||
},
|
||||
shareButton: toggleable_text_button(theme, {}),
|
||||
user_menu: user_menu(theme)
|
||||
user_menu: user_menu(theme),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,39 +1,39 @@
|
|||
import { ThemeSyntax } from "../../common";
|
||||
import { ThemeSyntax } from "../../common"
|
||||
|
||||
export const color = {
|
||||
default: {
|
||||
base: '#191724',
|
||||
surface: '#1f1d2e',
|
||||
overlay: '#26233a',
|
||||
muted: '#6e6a86',
|
||||
subtle: '#908caa',
|
||||
text: '#e0def4',
|
||||
love: '#eb6f92',
|
||||
gold: '#f6c177',
|
||||
rose: '#ebbcba',
|
||||
pine: '#31748f',
|
||||
foam: '#9ccfd8',
|
||||
iris: '#c4a7e7',
|
||||
highlightLow: '#21202e',
|
||||
highlightMed: '#403d52',
|
||||
highlightHigh: '#524f67',
|
||||
base: "#191724",
|
||||
surface: "#1f1d2e",
|
||||
overlay: "#26233a",
|
||||
muted: "#6e6a86",
|
||||
subtle: "#908caa",
|
||||
text: "#e0def4",
|
||||
love: "#eb6f92",
|
||||
gold: "#f6c177",
|
||||
rose: "#ebbcba",
|
||||
pine: "#31748f",
|
||||
foam: "#9ccfd8",
|
||||
iris: "#c4a7e7",
|
||||
highlightLow: "#21202e",
|
||||
highlightMed: "#403d52",
|
||||
highlightHigh: "#524f67",
|
||||
},
|
||||
moon: {
|
||||
base: '#232136',
|
||||
surface: '#2a273f',
|
||||
overlay: '#393552',
|
||||
muted: '#6e6a86',
|
||||
subtle: '#908caa',
|
||||
text: '#e0def4',
|
||||
love: '#eb6f92',
|
||||
gold: '#f6c177',
|
||||
rose: '#ea9a97',
|
||||
pine: '#3e8fb0',
|
||||
foam: '#9ccfd8',
|
||||
iris: '#c4a7e7',
|
||||
highlightLow: '#2a283e',
|
||||
highlightMed: '#44415a',
|
||||
highlightHigh: '#56526e',
|
||||
base: "#232136",
|
||||
surface: "#2a273f",
|
||||
overlay: "#393552",
|
||||
muted: "#6e6a86",
|
||||
subtle: "#908caa",
|
||||
text: "#e0def4",
|
||||
love: "#eb6f92",
|
||||
gold: "#f6c177",
|
||||
rose: "#ea9a97",
|
||||
pine: "#3e8fb0",
|
||||
foam: "#9ccfd8",
|
||||
iris: "#c4a7e7",
|
||||
highlightLow: "#2a283e",
|
||||
highlightMed: "#44415a",
|
||||
highlightHigh: "#56526e",
|
||||
},
|
||||
dawn: {
|
||||
base: "#faf4ed",
|
||||
|
@ -51,8 +51,8 @@ export const color = {
|
|||
highlightLow: "#f4ede8",
|
||||
highlightMed: "#dfdad9",
|
||||
highlightHigh: "#cecacd",
|
||||
}
|
||||
};
|
||||
},
|
||||
}
|
||||
|
||||
export const syntax = (c: typeof color.default): Partial<ThemeSyntax> => {
|
||||
return {
|
||||
|
|
|
@ -6,12 +6,12 @@ import {
|
|||
ThemeConfig,
|
||||
} from "../../common"
|
||||
|
||||
import { color as c, syntax } from "./common";
|
||||
import { color as c, syntax } from "./common"
|
||||
|
||||
const color = c.dawn
|
||||
|
||||
const green = chroma.mix(color.foam, "#10b981", 0.6, 'lab');
|
||||
const magenta = chroma.mix(color.love, color.pine, 0.5, 'lab');
|
||||
const green = chroma.mix(color.foam, "#10b981", 0.6, "lab")
|
||||
const magenta = chroma.mix(color.love, color.pine, 0.5, "lab")
|
||||
|
||||
export const theme: ThemeConfig = {
|
||||
name: "Rosé Pine Dawn",
|
||||
|
@ -21,7 +21,19 @@ export const theme: ThemeConfig = {
|
|||
licenseUrl: "https://github.com/edunfelt/base16-rose-pine-scheme",
|
||||
licenseFile: `${__dirname}/LICENSE`,
|
||||
inputColor: {
|
||||
neutral: chroma.scale([color.base, color.surface, color.highlightHigh, color.overlay, color.muted, color.subtle, color.text].reverse()).domain([0, 0.35, 0.45, 0.65, 0.7, 0.8, 0.9, 1]),
|
||||
neutral: chroma
|
||||
.scale(
|
||||
[
|
||||
color.base,
|
||||
color.surface,
|
||||
color.highlightHigh,
|
||||
color.overlay,
|
||||
color.muted,
|
||||
color.subtle,
|
||||
color.text,
|
||||
].reverse()
|
||||
)
|
||||
.domain([0, 0.35, 0.45, 0.65, 0.7, 0.8, 0.9, 1]),
|
||||
red: colorRamp(chroma(color.love)),
|
||||
orange: colorRamp(chroma(color.iris)),
|
||||
yellow: colorRamp(chroma(color.gold)),
|
||||
|
@ -32,6 +44,6 @@ export const theme: ThemeConfig = {
|
|||
magenta: colorRamp(chroma(magenta)),
|
||||
},
|
||||
override: {
|
||||
syntax: syntax(color)
|
||||
}
|
||||
syntax: syntax(color),
|
||||
},
|
||||
}
|
||||
|
|
|
@ -6,12 +6,12 @@ import {
|
|||
ThemeConfig,
|
||||
} from "../../common"
|
||||
|
||||
import { color as c, syntax } from "./common";
|
||||
import { color as c, syntax } from "./common"
|
||||
|
||||
const color = c.moon
|
||||
|
||||
const green = chroma.mix(color.foam, "#10b981", 0.6, 'lab');
|
||||
const magenta = chroma.mix(color.love, color.pine, 0.5, 'lab');
|
||||
const green = chroma.mix(color.foam, "#10b981", 0.6, "lab")
|
||||
const magenta = chroma.mix(color.love, color.pine, 0.5, "lab")
|
||||
|
||||
export const theme: ThemeConfig = {
|
||||
name: "Rosé Pine Moon",
|
||||
|
@ -21,7 +21,17 @@ export const theme: ThemeConfig = {
|
|||
licenseUrl: "https://github.com/edunfelt/base16-rose-pine-scheme",
|
||||
licenseFile: `${__dirname}/LICENSE`,
|
||||
inputColor: {
|
||||
neutral: chroma.scale([color.base, color.surface, color.highlightHigh, color.overlay, color.muted, color.subtle, color.text]).domain([0, 0.3, 0.55, 1]),
|
||||
neutral: chroma
|
||||
.scale([
|
||||
color.base,
|
||||
color.surface,
|
||||
color.highlightHigh,
|
||||
color.overlay,
|
||||
color.muted,
|
||||
color.subtle,
|
||||
color.text,
|
||||
])
|
||||
.domain([0, 0.3, 0.55, 1]),
|
||||
red: colorRamp(chroma(color.love)),
|
||||
orange: colorRamp(chroma(color.iris)),
|
||||
yellow: colorRamp(chroma(color.gold)),
|
||||
|
@ -32,6 +42,6 @@ export const theme: ThemeConfig = {
|
|||
magenta: colorRamp(chroma(magenta)),
|
||||
},
|
||||
override: {
|
||||
syntax: syntax(color)
|
||||
}
|
||||
syntax: syntax(color),
|
||||
},
|
||||
}
|
||||
|
|
|
@ -5,12 +5,12 @@ import {
|
|||
ThemeLicenseType,
|
||||
ThemeConfig,
|
||||
} from "../../common"
|
||||
import { color as c, syntax } from "./common";
|
||||
import { color as c, syntax } from "./common"
|
||||
|
||||
const color = c.default
|
||||
|
||||
const green = chroma.mix(color.foam, "#10b981", 0.6, 'lab');
|
||||
const magenta = chroma.mix(color.love, color.pine, 0.5, 'lab');
|
||||
const green = chroma.mix(color.foam, "#10b981", 0.6, "lab")
|
||||
const magenta = chroma.mix(color.love, color.pine, 0.5, "lab")
|
||||
|
||||
export const theme: ThemeConfig = {
|
||||
name: "Rosé Pine",
|
||||
|
@ -20,7 +20,15 @@ export const theme: ThemeConfig = {
|
|||
licenseUrl: "https://github.com/edunfelt/base16-rose-pine-scheme",
|
||||
licenseFile: `${__dirname}/LICENSE`,
|
||||
inputColor: {
|
||||
neutral: chroma.scale([color.base, color.surface, color.highlightHigh, color.overlay, color.muted, color.subtle, color.text]),
|
||||
neutral: chroma.scale([
|
||||
color.base,
|
||||
color.surface,
|
||||
color.highlightHigh,
|
||||
color.overlay,
|
||||
color.muted,
|
||||
color.subtle,
|
||||
color.text,
|
||||
]),
|
||||
red: colorRamp(chroma(color.love)),
|
||||
orange: colorRamp(chroma(color.iris)),
|
||||
yellow: colorRamp(chroma(color.gold)),
|
||||
|
@ -31,6 +39,6 @@ export const theme: ThemeConfig = {
|
|||
magenta: colorRamp(chroma(magenta)),
|
||||
},
|
||||
override: {
|
||||
syntax: syntax(color)
|
||||
}
|
||||
syntax: syntax(color),
|
||||
},
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue