From 9459394ea0127cc4220b80e13a9a812a5a6d899c Mon Sep 17 00:00:00 2001 From: Max Brunsfeld Date: Tue, 30 Jan 2024 19:59:13 -0800 Subject: [PATCH] Re-enable language plugin functionality with some fixes (#7105) Part of https://github.com/zed-industries/zed/issues/7096 * [x] Load all queries for language plugins, not just highlight query * [x] Auto-reload languages when changing the `plugins` directory * [x] Bump Tree-sitter for language loading and unloading fixes * [x] Figure out code signing Release Notes: - N/A --------- Co-authored-by: Antonio Co-authored-by: Marshall Bowers --- Cargo.lock | 414 +++++++++++++++++++++++++- Cargo.toml | 7 +- crates/language/src/language.rs | 46 ++- crates/zed/resources/zed.entitlements | 6 +- crates/zed/src/languages.rs | 86 ++++-- crates/zed/src/main.rs | 32 +- 6 files changed, 527 insertions(+), 64 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 82e3c827ae..d8b069e39c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -243,6 +243,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" + [[package]] name = "arrayref" version = "0.3.7" @@ -1852,6 +1858,105 @@ dependencies = [ "libc", ] +[[package]] +name = "cranelift-bforest" +version = "0.103.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "cranelift-entity", +] + +[[package]] +name = "cranelift-codegen" +version = "0.103.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "bumpalo", + "cranelift-bforest", + "cranelift-codegen-meta", + "cranelift-codegen-shared", + "cranelift-control", + "cranelift-entity", + "cranelift-isle", + "gimli", + "hashbrown 0.14.0", + "log", + "regalloc2", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-codegen-meta" +version = "0.103.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "cranelift-codegen-shared", +] + +[[package]] +name = "cranelift-codegen-shared" +version = "0.103.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" + +[[package]] +name = "cranelift-control" +version = "0.103.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "arbitrary", +] + +[[package]] +name = "cranelift-entity" +version = "0.103.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "cranelift-frontend" +version = "0.103.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "cranelift-codegen", + "log", + "smallvec", + "target-lexicon", +] + +[[package]] +name = "cranelift-isle" +version = "0.103.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" + +[[package]] +name = "cranelift-native" +version = "0.103.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "cranelift-codegen", + "libc", + "target-lexicon", +] + +[[package]] +name = "cranelift-wasm" +version = "0.103.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "cranelift-codegen", + "cranelift-entity", + "cranelift-frontend", + "itertools 0.10.5", + "log", + "smallvec", + "wasmparser", + "wasmtime-types", +] + [[package]] name = "crc" version = "3.0.1" @@ -2455,6 +2560,12 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "fallible-iterator" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649" + [[package]] name = "fallible-streaming-iterator" version = "0.1.9" @@ -3008,6 +3119,11 @@ name = "gimli" version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" +dependencies = [ + "fallible-iterator 0.3.0", + "indexmap 2.0.0", + "stable_deref_trait", +] [[package]] name = "git" @@ -3520,6 +3636,7 @@ checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" dependencies = [ "equivalent", "hashbrown 0.14.0", + "serde", ] [[package]] @@ -3926,6 +4043,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + [[package]] name = "libc" version = "0.2.152" @@ -4154,6 +4277,15 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +[[package]] +name = "mach" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +dependencies = [ + "libc", +] + [[package]] name = "mach2" version = "0.4.1" @@ -4232,6 +4364,15 @@ version = "2.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f232d6ef707e1956a43342693d2a31e72989554d58299d7a88738cc95b0d35c" +[[package]] +name = "memfd" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2cffa4ad52c6f791f4f8b15f0c05f9824b2ced1160e88cc393d64fff9a8ac64" +dependencies = [ + "rustix 0.38.30", +] + [[package]] name = "memmap2" version = "0.2.3" @@ -4889,6 +5030,9 @@ version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" dependencies = [ + "crc32fast", + "hashbrown 0.14.0", + "indexmap 2.0.0", "memchr", ] @@ -5812,6 +5956,15 @@ version = "2.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94" +[[package]] +name = "psm" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5787f7cda34e3033a72192c018bc5883100330f362ef279a8cbccfce8bb4e874" +dependencies = [ + "cc", +] + [[package]] name = "ptr_meta" version = "0.1.4" @@ -6063,6 +6216,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "regalloc2" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" +dependencies = [ + "hashbrown 0.13.2", + "log", + "rustc-hash", + "slice-group-by", + "smallvec", +] + [[package]] name = "regex" version = "1.9.5" @@ -6399,7 +6565,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "549b9d036d571d42e6e85d1c1425e2ac83491075078ca9a15be021c56b1641f2" dependencies = [ "bitflags 2.4.1", - "fallible-iterator", + "fallible-iterator 0.2.0", "fallible-streaming-iterator", "hashlink", "libsqlite3-sys", @@ -7211,6 +7377,12 @@ dependencies = [ "autocfg", ] +[[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.6" @@ -7317,6 +7489,12 @@ dependencies = [ "der", ] +[[package]] +name = "sptr" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a" + [[package]] name = "sqlez" version = "0.1.0" @@ -7573,6 +7751,12 @@ dependencies = [ "uuid 1.4.1", ] +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" @@ -7846,6 +8030,12 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "target-lexicon" +version = "0.12.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69758bda2e78f098e4ccb393021a0963bb3442eac05f135c30f61b7370bbafae" + [[package]] name = "tempfile" version = "3.9.0" @@ -8490,10 +8680,12 @@ dependencies = [ [[package]] name = "tree-sitter" version = "0.20.10" -source = "git+https://github.com/tree-sitter/tree-sitter?rev=31c40449749c4263a91a43593831b82229049a4c#31c40449749c4263a91a43593831b82229049a4c" +source = "git+https://github.com/tree-sitter/tree-sitter?rev=1d8975319c2d5de1bf710e7e21db25b0eee4bc66#1d8975319c2d5de1bf710e7e21db25b0eee4bc66" dependencies = [ "cc", "regex", + "wasmtime", + "wasmtime-c-api-impl", ] [[package]] @@ -9328,6 +9520,224 @@ version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +[[package]] +name = "wasm-encoder" +version = "0.38.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad2b51884de9c7f4fe2fd1043fccb8dcad4b1e29558146ee57a144d15779f3f" +dependencies = [ + "leb128", +] + +[[package]] +name = "wasmparser" +version = "0.118.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ee9723b928e735d53000dec9eae7b07a60e490c85ab54abb66659fc61bfcd9" +dependencies = [ + "indexmap 2.0.0", + "semver", +] + +[[package]] +name = "wasmtime" +version = "16.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "anyhow", + "bincode", + "bumpalo", + "cfg-if 1.0.0", + "indexmap 2.0.0", + "libc", + "log", + "object", + "once_cell", + "paste", + "serde", + "serde_derive", + "serde_json", + "target-lexicon", + "wasmparser", + "wasmtime-cranelift", + "wasmtime-environ", + "wasmtime-jit", + "wasmtime-runtime", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-asm-macros" +version = "16.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "wasmtime-c-api-impl" +version = "16.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "anyhow", + "log", + "once_cell", + "tracing", + "wasmtime", + "wasmtime-c-api-macros", +] + +[[package]] +name = "wasmtime-c-api-macros" +version = "0.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "wasmtime-cranelift" +version = "16.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "anyhow", + "cfg-if 1.0.0", + "cranelift-codegen", + "cranelift-control", + "cranelift-entity", + "cranelift-frontend", + "cranelift-native", + "cranelift-wasm", + "gimli", + "log", + "object", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-cranelift-shared", + "wasmtime-environ", + "wasmtime-versioned-export-macros", +] + +[[package]] +name = "wasmtime-cranelift-shared" +version = "16.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "anyhow", + "cranelift-codegen", + "cranelift-control", + "cranelift-native", + "gimli", + "object", + "target-lexicon", + "wasmtime-environ", +] + +[[package]] +name = "wasmtime-environ" +version = "16.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "anyhow", + "cranelift-entity", + "gimli", + "indexmap 2.0.0", + "log", + "object", + "serde", + "serde_derive", + "target-lexicon", + "thiserror", + "wasmparser", + "wasmtime-types", +] + +[[package]] +name = "wasmtime-jit" +version = "16.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "anyhow", + "bincode", + "cfg-if 1.0.0", + "gimli", + "log", + "object", + "rustix 0.38.30", + "serde", + "serde_derive", + "target-lexicon", + "wasmtime-environ", + "wasmtime-jit-icache-coherence", + "wasmtime-runtime", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-jit-icache-coherence" +version = "16.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-runtime" +version = "16.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "anyhow", + "cc", + "cfg-if 1.0.0", + "indexmap 2.0.0", + "libc", + "log", + "mach", + "memfd", + "memoffset 0.9.0", + "paste", + "psm", + "rustix 0.38.30", + "sptr", + "wasm-encoder", + "wasmtime-asm-macros", + "wasmtime-environ", + "wasmtime-versioned-export-macros", + "wasmtime-wmemcheck", + "windows-sys 0.48.0", +] + +[[package]] +name = "wasmtime-types" +version = "16.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "cranelift-entity", + "serde", + "serde_derive", + "thiserror", + "wasmparser", +] + +[[package]] +name = "wasmtime-versioned-export-macros" +version = "16.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "wasmtime-wmemcheck" +version = "16.0.0" +source = "git+https://github.com/bytecodealliance/wasmtime?rev=v16.0.0#6613acd1e4817957a4a7745125ef063b43c273a7" + [[package]] name = "web-sys" version = "0.3.64" diff --git a/Cargo.toml b/Cargo.toml index 148ef519c3..b224033101 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -130,7 +130,7 @@ thiserror = "1.0.29" tiktoken-rs = "0.5.7" time = { version = "0.3", features = ["serde", "serde-well-known"] } toml = "0.5" -tree-sitter = "0.20" +tree-sitter = { version = "0.20", features = ["wasm"] } tree-sitter-bash = { git = "https://github.com/tree-sitter/tree-sitter-bash", rev = "7331995b19b8f8aba2d5e26deb51d2195c18bc94" } tree-sitter-c = "0.20.1" tree-sitter-c-sharp = { git = "https://github.com/tree-sitter/tree-sitter-c-sharp", rev = "dd5e59721a5f8dae34604060833902b882023aaf" } @@ -168,10 +168,11 @@ tree-sitter-zig = { git = "https://github.com/maxxnino/tree-sitter-zig", rev = " unindent = "0.1.7" url = "2.2" uuid = { version = "1.1.2", features = ["v4"] } +wasmtime = "16" [patch.crates-io] -tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "31c40449749c4263a91a43593831b82229049a4c" } -# wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", rev = "v16.0.0" } +tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "1d8975319c2d5de1bf710e7e21db25b0eee4bc66" } +wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", rev = "v16.0.0" } [profile.dev] split-debuginfo = "unpacked" diff --git a/crates/language/src/language.rs b/crates/language/src/language.rs index 5b860a9de6..bd4c7f5d93 100644 --- a/crates/language/src/language.rs +++ b/crates/language/src/language.rs @@ -52,7 +52,7 @@ use std::{ }; use syntax_map::SyntaxSnapshot; use theme::{SyntaxTheme, Theme}; -use tree_sitter::{self, Query}; +use tree_sitter::{self, wasmtime, Query, WasmStore}; use unicase::UniCase; use util::{http::HttpClient, paths::PathExt}; use util::{post_inc, ResultExt, TryFutureExt as _, UnwrapFuture}; @@ -96,7 +96,9 @@ impl LspBinaryStatusSender { thread_local! { static PARSER: RefCell = { - RefCell::new(Parser::new()) + let mut parser = Parser::new(); + parser.set_wasm_store(WasmStore::new(WASM_ENGINE.clone()).unwrap()).unwrap(); + RefCell::new(parser) }; } @@ -104,6 +106,7 @@ lazy_static! { pub(crate) static ref NEXT_GRAMMAR_ID: AtomicUsize = Default::default(); /// A shared grammar for plain text, exposed for reuse by downstream crates. #[doc(hidden)] + pub static ref WASM_ENGINE: wasmtime::Engine = wasmtime::Engine::default(); pub static ref PLAIN_TEXT: Arc = Arc::new(Language::new( LanguageConfig { name: "Plain Text".into(), @@ -706,8 +709,8 @@ enum AvailableGrammar { get_queries: fn(&str) -> LanguageQueries, }, Wasm { - _grammar_name: Arc, - _path: Arc, + path: Arc, + get_queries: fn(&Path) -> LanguageQueries, }, } @@ -773,9 +776,6 @@ impl LanguageRegistry { } /// Clear out all of the loaded languages and reload them from scratch. - /// - /// This is useful in development, when queries have changed. - #[cfg(debug_assertions)] pub fn reload(&self) { self.state.write().reload(); } @@ -802,15 +802,17 @@ impl LanguageRegistry { }); } - pub fn register_wasm(&self, path: Arc, grammar_name: Arc, config: LanguageConfig) { + pub fn register_wasm( + &self, + path: Arc, + config: LanguageConfig, + get_queries: fn(&Path) -> LanguageQueries, + ) { let state = &mut *self.state.write(); state.available_languages.push(AvailableLanguage { id: post_inc(&mut state.next_available_language_id), config, - grammar: AvailableGrammar::Wasm { - _grammar_name: grammar_name, - _path: path, - }, + grammar: AvailableGrammar::Wasm { path, get_queries }, lsp_adapters: Vec::new(), loaded: false, }); @@ -944,8 +946,23 @@ impl LanguageRegistry { asset_dir, get_queries, } => (grammar, (get_queries)(asset_dir)), - AvailableGrammar::Wasm { .. } => { - Err(anyhow!("not supported"))? + AvailableGrammar::Wasm { path, get_queries } => { + let grammar_name = + &language.config.grammar_name.as_ref().ok_or_else( + || anyhow!("missing grammar name"), + )?; + let mut wasm_path = path.join(grammar_name.as_ref()); + wasm_path.set_extension("wasm"); + let wasm_bytes = std::fs::read(&wasm_path)?; + let grammar = PARSER.with(|parser| { + let mut parser = parser.borrow_mut(); + let mut store = parser.take_wasm_store().unwrap(); + let grammar = + store.load_language(&grammar_name, &wasm_bytes); + parser.set_wasm_store(store).unwrap(); + grammar + })?; + (grammar, get_queries(path.as_ref())) } }; Language::new(language.config, Some(grammar)) @@ -1172,7 +1189,6 @@ impl LanguageRegistryState { *self.subscription.0.borrow_mut() = (); } - #[cfg(debug_assertions)] fn reload(&mut self) { self.languages.clear(); self.version += 1; diff --git a/crates/zed/resources/zed.entitlements b/crates/zed/resources/zed.entitlements index f40a8a253a..cb4cd3dc69 100644 --- a/crates/zed/resources/zed.entitlements +++ b/crates/zed/resources/zed.entitlements @@ -6,6 +6,10 @@ com.apple.security.cs.allow-jit + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.device.audio-input com.apple.security.device.camera @@ -18,7 +22,5 @@ com.apple.security.personal-information.photos-library - diff --git a/crates/zed/src/languages.rs b/crates/zed/src/languages.rs index 8e923ac2fd..5ed9e43ec5 100644 --- a/crates/zed/src/languages.rs +++ b/crates/zed/src/languages.rs @@ -4,8 +4,8 @@ pub use language::*; use node_runtime::NodeRuntime; use rust_embed::RustEmbed; use settings::Settings; -use std::{borrow::Cow, str, sync::Arc}; -use util::{asset_str, paths::PLUGINS_DIR}; +use std::{borrow::Cow, fs, path::Path, str, sync::Arc}; +use util::{asset_str, paths::PLUGINS_DIR, ResultExt}; use self::{deno::DenoSettings, elixir::ElixirSettings}; @@ -303,10 +303,11 @@ pub fn init( let path = child.path(); let config_path = path.join("config.toml"); if let Ok(config) = std::fs::read(&config_path) { - let config: LanguageConfig = ::toml::from_slice(&config).unwrap(); - if let Some(grammar_name) = config.grammar_name.clone() { - languages.register_wasm(path.into(), grammar_name, config); - } + languages.register_wasm( + path.into(), + ::toml::from_slice(&config).unwrap(), + load_plugin_queries, + ); } } } @@ -338,27 +339,62 @@ fn load_config(name: &str) -> LanguageConfig { .unwrap() } -fn load_queries(name: &str) -> LanguageQueries { - LanguageQueries { - highlights: load_query(name, "/highlights"), - brackets: load_query(name, "/brackets"), - indents: load_query(name, "/indents"), - outline: load_query(name, "/outline"), - embedding: load_query(name, "/embedding"), - injections: load_query(name, "/injections"), - overrides: load_query(name, "/overrides"), - } -} +const QUERY_FILENAME_PREFIXES: &[( + &str, + fn(&mut LanguageQueries) -> &mut Option>, +)] = &[ + ("highlights", |q| &mut q.highlights), + ("brackets", |q| &mut q.brackets), + ("outline", |q| &mut q.outline), + ("indents", |q| &mut q.indents), + ("embedding", |q| &mut q.embedding), + ("injections", |q| &mut q.injections), + ("overrides", |q| &mut q.overrides), +]; -fn load_query(name: &str, filename_prefix: &str) -> Option> { - let mut result = None; +fn load_queries(name: &str) -> LanguageQueries { + let mut result = LanguageQueries::default(); for path in LanguageDir::iter() { - if let Some(remainder) = path.strip_prefix(name) { - if remainder.starts_with(filename_prefix) { - let contents = asset_str::(path.as_ref()); - match &mut result { - None => result = Some(contents), - Some(r) => r.to_mut().push_str(contents.as_ref()), + if let Some(remainder) = path.strip_prefix(name).and_then(|p| p.strip_prefix('/')) { + if !remainder.ends_with(".scm") { + continue; + } + for (name, query) in QUERY_FILENAME_PREFIXES { + if remainder.starts_with(name) { + let contents = asset_str::(path.as_ref()); + match query(&mut result) { + None => *query(&mut result) = Some(contents), + Some(r) => r.to_mut().push_str(contents.as_ref()), + } + } + } + } + } + result +} + +fn load_plugin_queries(root_path: &Path) -> LanguageQueries { + let mut result = LanguageQueries::default(); + if let Some(entries) = fs::read_dir(root_path).log_err() { + for entry in entries { + let Some(entry) = entry.log_err() else { + continue; + }; + let path = entry.path(); + if let Some(remainder) = path.strip_prefix(root_path).ok().and_then(|p| p.to_str()) { + if !remainder.ends_with(".scm") { + continue; + } + for (name, query) in QUERY_FILENAME_PREFIXES { + if remainder.starts_with(name) { + if let Some(contents) = fs::read_to_string(&path).log_err() { + match query(&mut result) { + None => *query(&mut result) = Some(contents.into()), + Some(r) => r.to_mut().push_str(contents.as_ref()), + } + } + break; + } } } } diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index ba651cf8e0..3e5a1adb6f 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -39,12 +39,13 @@ use std::{ Arc, }, thread, + time::Duration, }; use theme::{ActiveTheme, ThemeRegistry, ThemeSettings}; use util::{ async_maybe, http::{self, HttpClient, ZedHttpClient}, - paths::{self, CRASHES_DIR, CRASHES_RETIRED_DIR}, + paths::{self, CRASHES_DIR, CRASHES_RETIRED_DIR, PLUGINS_DIR}, ResultExt, }; use uuid::Uuid; @@ -894,26 +895,28 @@ fn load_embedded_fonts(cx: &AppContext) { .unwrap(); } -#[cfg(debug_assertions)] -async fn watch_languages(fs: Arc, languages: Arc) -> Option<()> { - use std::time::Duration; +async fn watch_languages(fs: Arc, languages: Arc) { + let reload_debounce = Duration::from_millis(250); - let mut events = fs - .watch( - "crates/zed/src/languages".as_ref(), - Duration::from_millis(100), + let mut events = fs.watch(PLUGINS_DIR.as_ref(), reload_debounce).await; + + #[cfg(debug_assertions)] + { + events = futures::stream::select( + events, + fs.watch("crates/zed/src/languages".as_ref(), reload_debounce) + .await, ) - .await; + .boxed(); + } + while (events.next().await).is_some() { languages.reload(); } - Some(()) } #[cfg(debug_assertions)] fn watch_file_types(fs: Arc, cx: &mut AppContext) { - use std::time::Duration; - cx.spawn(|cx| async move { let mut events = fs .watch( @@ -933,10 +936,5 @@ fn watch_file_types(fs: Arc, cx: &mut AppContext) { .detach() } -#[cfg(not(debug_assertions))] -async fn watch_languages(_: Arc, _: Arc) -> Option<()> { - None -} - #[cfg(not(debug_assertions))] fn watch_file_types(_fs: Arc, _cx: &mut AppContext) {}