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 <antonio@zed.dev>
Co-authored-by: Marshall Bowers <elliott.codes@gmail.com>
This commit is contained in:
Max Brunsfeld 2024-01-30 19:59:13 -08:00 committed by GitHub
parent db99d4fef1
commit 9459394ea0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 527 additions and 64 deletions

View file

@ -6,6 +6,10 @@
<true/>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<!-- <key>com.apple.security.cs.disable-library-validation</key>
<true/> -->
<key>com.apple.security.device.audio-input</key>
<true/>
<key>com.apple.security.device.camera</key>
@ -18,7 +22,5 @@
<true/>
<key>com.apple.security.personal-information.photos-library</key>
<true/>
<!-- <key>com.apple.security.cs.disable-library-validation</key>
<true/> -->
</dict>
</plist>

View file

@ -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<Cow<'static, str>>,
)] = &[
("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<Cow<'static, str>> {
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::<LanguageDir>(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::<LanguageDir>(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;
}
}
}
}

View file

@ -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<dyn fs::Fs>, languages: Arc<LanguageRegistry>) -> Option<()> {
use std::time::Duration;
async fn watch_languages(fs: Arc<dyn fs::Fs>, languages: Arc<LanguageRegistry>) {
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<dyn fs::Fs>, 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<dyn fs::Fs>, cx: &mut AppContext) {
.detach()
}
#[cfg(not(debug_assertions))]
async fn watch_languages(_: Arc<dyn fs::Fs>, _: Arc<LanguageRegistry>) -> Option<()> {
None
}
#[cfg(not(debug_assertions))]
fn watch_file_types(_fs: Arc<dyn fs::Fs>, _cx: &mut AppContext) {}