Add logic for managing language and theme extensions (#7467)

This PR adds the initial support for loading extensions in Zed.

### Extensions Directory

Extensions are loaded from the extensions directory.

The extensions directory has the following structure:

```
extensions/
  installed/
    extension-a/
      grammars/
      languages/
    extension-b/
      themes/
  manifest.json
```

The `manifest.json` file is used internally by Zed to keep track of
which extensions are installed. This file should be maintained
automatically, and shouldn't require any direct interaction with it.

Extensions can provide Tree-sitter grammars, languages, and themes.

Release Notes:

- N/A

---------

Co-authored-by: Marshall <marshall@zed.dev>
This commit is contained in:
Max Brunsfeld 2024-02-07 12:14:50 -08:00 committed by GitHub
parent 6b598a07d9
commit 6edeea7c8a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
77 changed files with 1503 additions and 387 deletions

View file

@ -44,6 +44,7 @@ db.workspace = true
diagnostics.workspace = true
editor.workspace = true
env_logger.workspace = true
extension.workspace = true
feature_flags.workspace = true
feedback.workspace = true
file_finder.workspace = true

View file

@ -4,8 +4,8 @@ pub use language::*;
use node_runtime::NodeRuntime;
use rust_embed::RustEmbed;
use settings::Settings;
use std::{borrow::Cow, fs, path::Path, str, sync::Arc};
use util::{asset_str, paths::PLUGINS_DIR, ResultExt};
use std::{str, sync::Arc};
use util::asset_str;
use self::{deno::DenoSettings, elixir::ElixirSettings};
@ -62,30 +62,69 @@ pub fn init(
ElixirSettings::register(cx);
DenoSettings::register(cx);
let language = |name, grammar, adapters| {
languages.register(name, load_config(name), grammar, adapters, load_queries)
languages.add_grammars([
("bash", tree_sitter_bash::language()),
("beancount", tree_sitter_beancount::language()),
("c", tree_sitter_c::language()),
("c_sharp", tree_sitter_c_sharp::language()),
("cpp", tree_sitter_cpp::language()),
("css", tree_sitter_css::language()),
("elixir", tree_sitter_elixir::language()),
("elm", tree_sitter_elm::language()),
(
"embedded_template",
tree_sitter_embedded_template::language(),
),
("erlang", tree_sitter_erlang::language()),
("gitcommit", tree_sitter_gitcommit::language()),
("gleam", tree_sitter_gleam::language()),
("glsl", tree_sitter_glsl::language()),
("go", tree_sitter_go::language()),
("gomod", tree_sitter_gomod::language()),
("gowork", tree_sitter_gowork::language()),
("haskell", tree_sitter_haskell::language()),
("hcl", tree_sitter_hcl::language()),
("heex", tree_sitter_heex::language()),
("html", tree_sitter_html::language()),
("json", tree_sitter_json::language()),
("lua", tree_sitter_lua::language()),
("markdown", tree_sitter_markdown::language()),
("nix", tree_sitter_nix::language()),
("nu", tree_sitter_nu::language()),
("ocaml", tree_sitter_ocaml::language_ocaml()),
(
"ocaml_interface",
tree_sitter_ocaml::language_ocaml_interface(),
),
("php", tree_sitter_php::language_php()),
("proto", tree_sitter_proto::language()),
("purescript", tree_sitter_purescript::language()),
("python", tree_sitter_python::language()),
("racket", tree_sitter_racket::language()),
("ruby", tree_sitter_ruby::language()),
("rust", tree_sitter_rust::language()),
("scheme", tree_sitter_scheme::language()),
("svelte", tree_sitter_svelte::language()),
("toml", tree_sitter_toml::language()),
("tsx", tree_sitter_typescript::language_tsx()),
("typescript", tree_sitter_typescript::language_typescript()),
("uiua", tree_sitter_uiua::language()),
("vue", tree_sitter_vue::language()),
("yaml", tree_sitter_yaml::language()),
("zig", tree_sitter_zig::language()),
]);
let language = |name: &'static str, adapters| {
languages.register(name, load_config(name), adapters, load_queries)
};
language("bash", tree_sitter_bash::language(), vec![]);
language("beancount", tree_sitter_beancount::language(), vec![]);
language(
"c",
tree_sitter_c::language(),
vec![Arc::new(c::CLspAdapter) as Arc<dyn LspAdapter>],
);
language(
"cpp",
tree_sitter_cpp::language(),
vec![Arc::new(c::CLspAdapter)],
);
language(
"csharp",
tree_sitter_c_sharp::language(),
vec![Arc::new(csharp::OmniSharpAdapter {})],
);
language("bash", vec![]);
language("beancount", vec![]);
language("c", vec![Arc::new(c::CLspAdapter) as Arc<dyn LspAdapter>]);
language("cpp", vec![Arc::new(c::CLspAdapter)]);
language("csharp", vec![Arc::new(csharp::OmniSharpAdapter {})]);
language(
"css",
tree_sitter_css::language(),
vec![
Arc::new(css::CssLspAdapter::new(node_runtime.clone())),
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
@ -95,53 +134,32 @@ pub fn init(
match &ElixirSettings::get(None, cx).lsp {
elixir::ElixirLspSetting::ElixirLs => language(
"elixir",
tree_sitter_elixir::language(),
vec![
Arc::new(elixir::ElixirLspAdapter),
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
],
),
elixir::ElixirLspSetting::NextLs => language(
"elixir",
tree_sitter_elixir::language(),
vec![Arc::new(elixir::NextLspAdapter)],
),
elixir::ElixirLspSetting::NextLs => {
language("elixir", vec![Arc::new(elixir::NextLspAdapter)])
}
elixir::ElixirLspSetting::Local { path, arguments } => language(
"elixir",
tree_sitter_elixir::language(),
vec![Arc::new(elixir::LocalLspAdapter {
path: path.clone(),
arguments: arguments.clone(),
})],
),
}
language("gitcommit", tree_sitter_gitcommit::language(), vec![]);
language(
"erlang",
tree_sitter_erlang::language(),
vec![Arc::new(erlang::ErlangLspAdapter)],
);
language("gitcommit", vec![]);
language("erlang", vec![Arc::new(erlang::ErlangLspAdapter)]);
language(
"gleam",
tree_sitter_gleam::language(),
vec![Arc::new(gleam::GleamLspAdapter)],
);
language(
"go",
tree_sitter_go::language(),
vec![Arc::new(go::GoLspAdapter)],
);
language("gomod", tree_sitter_gomod::language(), vec![]);
language("gowork", tree_sitter_gowork::language(), vec![]);
language(
"zig",
tree_sitter_zig::language(),
vec![Arc::new(zig::ZlsAdapter)],
);
language("gleam", vec![Arc::new(gleam::GleamLspAdapter)]);
language("go", vec![Arc::new(go::GoLspAdapter)]);
language("gomod", vec![]);
language("gowork", vec![]);
language("zig", vec![Arc::new(zig::ZlsAdapter)]);
language(
"heex",
tree_sitter_heex::language(),
vec![
Arc::new(elixir::ElixirLspAdapter),
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
@ -149,48 +167,32 @@ pub fn init(
);
language(
"json",
tree_sitter_json::language(),
vec![Arc::new(json::JsonLspAdapter::new(
node_runtime.clone(),
languages.clone(),
))],
);
language("markdown", tree_sitter_markdown::language(), vec![]);
language("markdown", vec![]);
language(
"python",
tree_sitter_python::language(),
vec![Arc::new(python::PythonLspAdapter::new(
node_runtime.clone(),
))],
);
language(
"rust",
tree_sitter_rust::language(),
vec![Arc::new(rust::RustLspAdapter)],
);
language(
"toml",
tree_sitter_toml::language(),
vec![Arc::new(toml::TaploLspAdapter)],
);
language("rust", vec![Arc::new(rust::RustLspAdapter)]);
language("toml", vec![Arc::new(toml::TaploLspAdapter)]);
match &DenoSettings::get(None, cx).enable {
true => {
language(
"tsx",
tree_sitter_typescript::language_tsx(),
vec![
Arc::new(deno::DenoLspAdapter::new()),
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
],
);
language(
"typescript",
tree_sitter_typescript::language_typescript(),
vec![Arc::new(deno::DenoLspAdapter::new())],
);
language("typescript", vec![Arc::new(deno::DenoLspAdapter::new())]);
language(
"javascript",
tree_sitter_typescript::language_tsx(),
vec![
Arc::new(deno::DenoLspAdapter::new()),
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
@ -200,7 +202,6 @@ pub fn init(
false => {
language(
"tsx",
tree_sitter_typescript::language_tsx(),
vec![
Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
@ -209,7 +210,6 @@ pub fn init(
);
language(
"typescript",
tree_sitter_typescript::language_typescript(),
vec![
Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
@ -217,7 +217,6 @@ pub fn init(
);
language(
"javascript",
tree_sitter_typescript::language_tsx(),
vec![
Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
@ -227,47 +226,31 @@ pub fn init(
}
}
language(
"haskell",
tree_sitter_haskell::language(),
vec![Arc::new(haskell::HaskellLanguageServer {})],
);
language("haskell", vec![Arc::new(haskell::HaskellLanguageServer {})]);
language(
"html",
tree_sitter_html::language(),
vec![
Arc::new(html::HtmlLspAdapter::new(node_runtime.clone())),
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
],
);
language(
"ruby",
tree_sitter_ruby::language(),
vec![Arc::new(ruby::RubyLanguageServer)],
);
language("ruby", vec![Arc::new(ruby::RubyLanguageServer)]);
language(
"erb",
tree_sitter_embedded_template::language(),
vec![
Arc::new(ruby::RubyLanguageServer),
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
],
);
language("scheme", tree_sitter_scheme::language(), vec![]);
language("racket", tree_sitter_racket::language(), vec![]);
language(
"lua",
tree_sitter_lua::language(),
vec![Arc::new(lua::LuaLspAdapter)],
);
language("scheme", vec![]);
language("racket", vec![]);
language("lua", vec![Arc::new(lua::LuaLspAdapter)]);
language(
"yaml",
tree_sitter_yaml::language(),
vec![Arc::new(yaml::YamlLspAdapter::new(node_runtime.clone()))],
);
language(
"svelte",
tree_sitter_svelte::language(),
vec![
Arc::new(svelte::SvelteLspAdapter::new(node_runtime.clone())),
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
@ -275,7 +258,6 @@ pub fn init(
);
language(
"php",
tree_sitter_php::language_php(),
vec![
Arc::new(php::IntelephenseLspAdapter::new(node_runtime.clone())),
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
@ -284,62 +266,24 @@ pub fn init(
language(
"purescript",
tree_sitter_purescript::language(),
vec![Arc::new(purescript::PurescriptLspAdapter::new(
node_runtime.clone(),
))],
);
language(
"elm",
tree_sitter_elm::language(),
vec![Arc::new(elm::ElmLspAdapter::new(node_runtime.clone()))],
);
language("glsl", tree_sitter_glsl::language(), vec![]);
language("nix", tree_sitter_nix::language(), vec![]);
language(
"nu",
tree_sitter_nu::language(),
vec![Arc::new(nu::NuLanguageServer {})],
);
language(
"ocaml",
tree_sitter_ocaml::language_ocaml(),
vec![Arc::new(ocaml::OCamlLspAdapter)],
);
language(
"ocaml-interface",
tree_sitter_ocaml::language_ocaml_interface(),
vec![Arc::new(ocaml::OCamlLspAdapter)],
);
language(
"vue",
tree_sitter_vue::language(),
vec![Arc::new(vue::VueLspAdapter::new(node_runtime))],
);
language(
"uiua",
tree_sitter_uiua::language(),
vec![Arc::new(uiua::UiuaLanguageServer {})],
);
language("proto", tree_sitter_proto::language(), vec![]);
language("terraform", tree_sitter_hcl::language(), vec![]);
language("hcl", tree_sitter_hcl::language(), vec![]);
if let Ok(children) = std::fs::read_dir(&*PLUGINS_DIR) {
for child in children {
if let Ok(child) = child {
let path = child.path();
let config_path = path.join("config.toml");
if let Ok(config) = std::fs::read(&config_path) {
languages.register_wasm(
path.into(),
::toml::from_slice(&config).unwrap(),
load_plugin_queries,
);
}
}
}
}
language("glsl", vec![]);
language("nix", vec![]);
language("nu", vec![Arc::new(nu::NuLanguageServer {})]);
language("ocaml", vec![Arc::new(ocaml::OCamlLspAdapter)]);
language("ocaml-interface", vec![Arc::new(ocaml::OCamlLspAdapter)]);
language("vue", vec![Arc::new(vue::VueLspAdapter::new(node_runtime))]);
language("uiua", vec![Arc::new(uiua::UiuaLanguageServer {})]);
language("proto", vec![]);
language("terraform", vec![]);
language("hcl", vec![]);
}
#[cfg(any(test, feature = "test-support"))]
@ -367,20 +311,6 @@ fn load_config(name: &str) -> LanguageConfig {
.unwrap()
}
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),
("redactions", |q| &mut q.redactions),
];
fn load_queries(name: &str) -> LanguageQueries {
let mut result = LanguageQueries::default();
for path in LanguageDir::iter() {
@ -401,32 +331,3 @@ fn load_queries(name: &str) -> LanguageQueries {
}
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;
}
}
}
}
}
result
}

View file

@ -1,4 +1,5 @@
name = "Shell Script"
grammar = "bash"
path_suffixes = ["sh", "bash", "bashrc", "bash_profile", "bash_aliases", "bash_logout", "profile", "zsh", "zshrc", "zshenv", "zsh_profile", "zsh_aliases", "zsh_histfile", "zlogin", "zprofile", ".env"]
line_comments = ["# "]
first_line_pattern = "^#!.*\\b(?:ba|z)?sh\\b"

View file

@ -1,3 +1,4 @@
name = "Beancount"
grammar = "beancount"
path_suffixes = ["beancount"]
brackets = [{ start = "\"", end = "\"", close = false, newline = false }]

View file

@ -1,4 +1,5 @@
name = "C"
grammar = "c"
path_suffixes = ["c"]
line_comments = ["// "]
autoclose_before = ";:.,=}])>"

View file

@ -1,4 +1,5 @@
name = "C++"
grammar = "cpp"
path_suffixes = ["cc", "cpp", "h", "hpp", "cxx", "hxx", "inl"]
line_comments = ["// "]
autoclose_before = ";:.,=}])>"

View file

@ -1,4 +1,5 @@
name = "CSharp"
grammar = "c_sharp"
path_suffixes = ["cs"]
line_comments = ["// "]
autoclose_before = ";:.,=}])>"

View file

@ -1,4 +1,5 @@
name = "CSS"
grammar = "css"
path_suffixes = ["css"]
autoclose_before = ";:.,=}])>"
brackets = [

View file

@ -1,4 +1,5 @@
name = "Elixir"
grammar = "elixir"
path_suffixes = ["ex", "exs"]
line_comments = ["# "]
autoclose_before = ";:.,=}])>"

View file

@ -1,4 +1,5 @@
name = "Elm"
grammar = "elm"
path_suffixes = ["elm"]
line_comments = ["-- "]
block_comment = ["{- ", " -}"]

View file

@ -1,4 +1,5 @@
name = "ERB"
grammar = "embedded_template"
path_suffixes = ["erb"]
autoclose_before = ">})"
brackets = [

View file

@ -1,4 +1,5 @@
name = "Erlang"
grammar = "erlang"
# TODO: support parsing rebar.config files
# # https://github.com/WhatsApp/tree-sitter-erlang/issues/3
path_suffixes = ["erl", "hrl", "app.src", "escript", "xrl", "yrl", "Emakefile", "rebar.config"]

View file

@ -1,4 +1,5 @@
name = "Git Commit"
grammar = "git_commit"
path_suffixes = [
# Refer to https://github.com/neovim/neovim/blob/master/runtime/lua/vim/filetype.lua#L1286-L1290
"TAG_EDITMSG",

View file

@ -1,4 +1,5 @@
name = "Gleam"
grammar = "gleam"
path_suffixes = ["gleam"]
line_comments = ["// ", "/// "]
autoclose_before = ";:.,=}])>"

View file

@ -1,4 +1,5 @@
name = "GLSL"
grammar = "glsl"
path_suffixes = ["vert", "frag", "tesc", "tese", "geom", "comp"]
line_comments = ["// "]
block_comment = ["/* ", " */"]

View file

@ -1,4 +1,5 @@
name = "Go"
grammar = "go"
path_suffixes = ["go"]
line_comments = ["// "]
autoclose_before = ";:.,=}])>"

View file

@ -1,4 +1,5 @@
name = "Go Mod"
grammar = "go"
path_suffixes = ["mod"]
line_comments = ["//"]
autoclose_before = ")"

View file

@ -1,4 +1,5 @@
name = "Go Work"
grammar = "go_work"
path_suffixes = ["work"]
line_comments = ["//"]
autoclose_before = ")"

View file

@ -1,4 +1,5 @@
name = "Haskell"
grammar = "haskell"
path_suffixes = ["hs"]
autoclose_before = ",=)}]"
line_comments = ["-- "]

View file

@ -1,4 +1,5 @@
name = "HCL"
grammar = "hcl"
path_suffixes = ["hcl"]
line_comments = ["# ", "// "]
block_comment = ["/*", "*/"]

View file

@ -1,4 +1,5 @@
name = "HEEX"
grammar = "heex"
path_suffixes = ["heex"]
autoclose_before = ">})"
brackets = [

View file

@ -1,4 +1,5 @@
name = "HTML"
grammar = "html"
path_suffixes = ["html", "htm", "shtml"]
autoclose_before = ">})"
block_comment = ["<!-- ", " -->"]

View file

@ -1,4 +1,5 @@
name = "JavaScript"
grammar = "tsx"
path_suffixes = ["js", "jsx", "mjs", "cjs"]
first_line_pattern = '^#!.*\bnode\b'
line_comments = ["// "]

View file

@ -1,4 +1,5 @@
name = "JSON"
grammar = "json"
path_suffixes = ["json"]
line_comments = ["// "]
autoclose_before = ",]}"

View file

@ -1,4 +1,5 @@
name = "Lua"
grammar = "lua"
path_suffixes = ["lua"]
line_comments = ["-- "]
autoclose_before = ",]}"

View file

@ -1,4 +1,5 @@
name = "Markdown"
grammar = "markdown"
path_suffixes = ["md", "mdx"]
word_characters = ["-"]
brackets = [

View file

@ -1,4 +1,5 @@
name = "Nix"
grammar = "nix"
path_suffixes = ["nix"]
line_comments = ["# "]
block_comment = ["/* ", " */"]

View file

@ -1,4 +1,5 @@
name = "Nu"
grammar = "nu"
path_suffixes = ["nu"]
line_comments = ["# "]
autoclose_before = ";:.,=}])>` \n\t\""

View file

@ -1,4 +1,5 @@
name = "OCaml Interface"
grammar = "ocaml_interface"
path_suffixes = ["mli"]
block_comment = ["(* ", "*)"]
autoclose_before = ";,=)}"
@ -8,6 +9,6 @@ brackets = [
{ start = "[", end = "]", close = true, newline = true },
{ start = "(", end = ")", close = true, newline = true },
{ start = "sig", end = " end", close = true, newline = true },
# HACK: For some reason `object` alone does not work
# HACK: For some reason `object` alone does not work
{ start = "object ", end = "end", close = true, newline = true },
]

View file

@ -1,8 +1,9 @@
name = "OCaml"
grammar = "ocaml"
path_suffixes = ["ml"]
block_comment = ["(* ", "*)"]
autoclose_before = ";,=)}]"
brackets = [
brackets = [
{ start = "{", end = "}", close = true, newline = true },
{ start = "<", end = ">", close = true, newline = true },
{ start = "[", end = "]", close = true, newline = true },

View file

@ -1,4 +1,5 @@
name = "PHP"
grammar = "php"
path_suffixes = ["php"]
first_line_pattern = '^#!.*php'
line_comments = ["// ", "# "]

View file

@ -1,4 +1,5 @@
name = "proto"
grammar = "proto"
path_suffixes = ["proto"]
line_comments = ["// "]
autoclose_before = ";:.,=}])>"

View file

@ -1,4 +1,5 @@
name = "PureScript"
grammar = "purescript"
path_suffixes = ["purs"]
autoclose_before = ",=)}]"
line_comments = ["-- "]

View file

@ -1,4 +1,5 @@
name = "Python"
grammar = "python"
path_suffixes = ["py", "pyi", "mpy"]
first_line_pattern = '^#!.*\bpython[0-9.]*\b'
line_comments = ["# "]

View file

@ -1,4 +1,5 @@
name = "Racket"
grammar = "racket"
path_suffixes = ["rkt"]
line_comments = ["; "]
autoclose_before = "])"

View file

@ -1,4 +1,5 @@
name = "Ruby"
grammar = "ruby"
path_suffixes = [
"rb",
"Gemfile",

View file

@ -1,4 +1,5 @@
name = "Rust"
grammar = "rust"
path_suffixes = ["rs"]
line_comments = ["// ", "/// ", "//! "]
autoclose_before = ";:.,=}])>"

View file

@ -1,4 +1,5 @@
name = "Scheme"
grammar = "scheme"
path_suffixes = ["scm", "ss"]
line_comments = ["; "]
autoclose_before = "])"

View file

@ -1,4 +1,5 @@
name = "Svelte"
grammar = "svelte"
path_suffixes = ["svelte"]
block_comment = ["<!-- ", " -->"]
autoclose_before = ";:.,=}])>"

View file

@ -1,4 +1,5 @@
name = "Terraform"
grammar = "terraform"
path_suffixes = ["tf", "tfvars"]
line_comments = ["# ", "// "]
block_comment = ["/*", "*/"]

View file

@ -1,4 +1,5 @@
name = "TOML"
grammar = "toml"
path_suffixes = ["Cargo.lock", "toml"]
line_comments = ["# "]
autoclose_before = ",]}"

View file

@ -1,4 +1,5 @@
name = "TSX"
grammar = "tsx"
path_suffixes = ["tsx"]
line_comments = ["// "]
autoclose_before = ";:.,=}])>"

View file

@ -1,4 +1,5 @@
name = "TypeScript"
grammar = "typescript"
path_suffixes = ["ts", "cts", "d.cts", "d.mts", "mts"]
line_comments = ["// "]
autoclose_before = ";:.,=}])>"

View file

@ -1,4 +1,5 @@
name = "Uiua"
grammar = "uiua"
path_suffixes = ["ua"]
line_comments = ["# "]
autoclose_before = ")]}\""

View file

@ -1,4 +1,5 @@
name = "Vue.js"
grammar = "vue"
path_suffixes = ["vue"]
block_comment = ["<!-- ", " -->"]
autoclose_before = ";:.,=}])>"

View file

@ -1,4 +1,5 @@
name = "YAML"
grammar = "yaml"
path_suffixes = ["yml", "yaml"]
line_comments = ["# "]
autoclose_before = ",]}"

View file

@ -1,4 +1,5 @@
name = "Zig"
grammar = "zig"
path_suffixes = ["zig"]
line_comments = ["// "]
autoclose_before = ";:.,=}])>"

View file

@ -47,7 +47,7 @@ use theme::{ActiveTheme, SystemAppearance, ThemeRegistry, ThemeSettings};
use util::{
async_maybe,
http::{self, HttpClient, ZedHttpClient},
paths::{self, CRASHES_DIR, CRASHES_RETIRED_DIR, PLUGINS_DIR},
paths::{self, CRASHES_DIR, CRASHES_RETIRED_DIR},
ResultExt,
};
use uuid::Uuid;
@ -173,6 +173,8 @@ fn main() {
);
assistant::init(cx);
extension::init(fs.clone(), languages.clone(), ThemeRegistry::global(cx), cx);
load_user_themes_in_background(fs.clone(), cx);
watch_themes(fs.clone(), cx);
@ -976,20 +978,13 @@ fn watch_themes(fs: Arc<dyn fs::Fs>, cx: &mut AppContext) {
.detach()
}
#[cfg(debug_assertions)]
async fn watch_languages(fs: Arc<dyn fs::Fs>, languages: Arc<LanguageRegistry>) {
let reload_debounce = Duration::from_millis(250);
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,
)
.boxed();
}
let mut events = fs
.watch("crates/zed/src/languages".as_ref(), reload_debounce)
.await;
while (events.next().await).is_some() {
languages.reload();
@ -1019,3 +1014,6 @@ fn watch_file_types(fs: Arc<dyn fs::Fs>, cx: &mut AppContext) {
#[cfg(not(debug_assertions))]
fn watch_file_types(_fs: Arc<dyn fs::Fs>, _cx: &mut AppContext) {}
#[cfg(not(debug_assertions))]
async fn watch_languages(_fs: Arc<dyn fs::Fs>, _languages: Arc<LanguageRegistry>) {}

View file

@ -739,7 +739,7 @@ mod tests {
actions, Action, AnyWindowHandle, AppContext, AssetSource, Entity, TestAppContext,
VisualTestContext, WindowHandle,
};
use language::LanguageRegistry;
use language::{LanguageMatcher, LanguageRegistry};
use project::{project_settings::ProjectSettings, Project, ProjectPath};
use serde_json::json;
use settings::{handle_settings_file_changes, watch_config_file, SettingsStore};
@ -2742,7 +2742,10 @@ mod tests {
Arc::new(language::Language::new(
language::LanguageConfig {
name: "Rust".into(),
path_suffixes: vec!["rs".to_string()],
matcher: LanguageMatcher {
path_suffixes: vec!["rs".to_string()],
..Default::default()
},
..Default::default()
},
Some(tree_sitter_rust::language()),