Detailed changes
@@ -8125,6 +8125,15 @@ dependencies = [
"tree-sitter",
]
+[[package]]
+name = "tree-sitter-svelte"
+version = "0.10.2"
+source = "git+https://github.com/Himujjal/tree-sitter-svelte?rev=697bb515471871e85ff799ea57a76298a71a9cca#697bb515471871e85ff799ea57a76298a71a9cca"
+dependencies = [
+ "cc",
+ "tree-sitter",
+]
+
[[package]]
name = "tree-sitter-toml"
version = "0.5.1"
@@ -9555,6 +9564,7 @@ dependencies = [
"tree-sitter-ruby",
"tree-sitter-rust",
"tree-sitter-scheme",
+ "tree-sitter-svelte",
"tree-sitter-toml",
"tree-sitter-typescript 0.20.2 (git+https://github.com/tree-sitter/tree-sitter-typescript?rev=5d20856f34315b068c41edaee2ac8a100081d259)",
"tree-sitter-yaml",
@@ -122,6 +122,7 @@ tree-sitter-html = "0.19.0"
tree-sitter-scheme = { git = "https://github.com/6cdh/tree-sitter-scheme", rev = "af0fd1fa452cb2562dc7b5c8a8c55551c39273b9"}
tree-sitter-racket = { git = "https://github.com/zed-industries/tree-sitter-racket", rev = "eb010cf2c674c6fd9a6316a84e28ef90190fe51a"}
tree-sitter-yaml = { git = "https://github.com/zed-industries/tree-sitter-yaml", rev = "f545a41f57502e1b5ddf2a6668896c1b0620f930"}
+tree-sitter-svelte = { git = "https://github.com/Himujjal/tree-sitter-svelte", rev = "697bb515471871e85ff799ea57a76298a71a9cca"}
tree-sitter-lua = "0.0.14"
url = "2.2"
urlencoding = "2.1.2"
@@ -17,6 +17,7 @@ mod python;
mod ruby;
mod rust;
mod typescript;
+mod svelte;
mod yaml;
// 1. Add tree-sitter-{language} parser to zed crate
@@ -135,7 +136,12 @@ pub fn init(languages: Arc<LanguageRegistry>, node_runtime: Arc<NodeRuntime>) {
language(
"yaml",
tree_sitter_yaml::language(),
- vec![Arc::new(yaml::YamlLspAdapter::new(node_runtime))],
+ vec![Arc::new(yaml::YamlLspAdapter::new(node_runtime.clone()))],
+ );
+ language(
+ "svelte",
+ tree_sitter_svelte::language(),
+ vec![Arc::new(svelte::SvelteLspAdapter::new(node_runtime.clone()))],
);
}
@@ -0,0 +1,126 @@
+use anyhow::{anyhow, Result};
+use async_trait::async_trait;
+use futures::StreamExt;
+use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
+use lsp::LanguageServerBinary;
+use node_runtime::NodeRuntime;
+use serde_json::json;
+use smol::fs;
+use std::{
+ any::Any,
+ ffi::OsString,
+ path::{Path, PathBuf},
+ sync::Arc,
+};
+use util::ResultExt;
+
+const SERVER_PATH: &'static str =
+ "node_modules/svelte-language-server/bin/server.js";
+
+fn server_binary_arguments(server_path: &Path) -> Vec<OsString> {
+ vec![server_path.into(), "--stdio".into()]
+}
+
+pub struct SvelteLspAdapter {
+ node: Arc<NodeRuntime>,
+}
+
+impl SvelteLspAdapter {
+ pub fn new(node: Arc<NodeRuntime>) -> Self {
+ SvelteLspAdapter { node }
+ }
+}
+
+#[async_trait]
+impl LspAdapter for SvelteLspAdapter {
+ async fn name(&self) -> LanguageServerName {
+ LanguageServerName("svelte-language-server".into())
+ }
+
+ async fn fetch_latest_server_version(
+ &self,
+ _: &dyn LspAdapterDelegate,
+ ) -> Result<Box<dyn 'static + Any + Send>> {
+ Ok(Box::new(
+ self.node
+ .npm_package_latest_version("svelte-language-server")
+ .await?,
+ ) as Box<_>)
+ }
+
+ async fn fetch_server_binary(
+ &self,
+ version: Box<dyn 'static + Send + Any>,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Result<LanguageServerBinary> {
+ let version = version.downcast::<String>().unwrap();
+ let server_path = container_dir.join(SERVER_PATH);
+
+ if fs::metadata(&server_path).await.is_err() {
+ self.node
+ .npm_install_packages(
+ &container_dir,
+ [("svelte-language-server", version.as_str())],
+ )
+ .await?;
+ }
+
+ Ok(LanguageServerBinary {
+ path: self.node.binary_path().await?,
+ arguments: server_binary_arguments(&server_path),
+ })
+ }
+
+ async fn cached_server_binary(
+ &self,
+ container_dir: PathBuf,
+ _: &dyn LspAdapterDelegate,
+ ) -> Option<LanguageServerBinary> {
+ get_cached_server_binary(container_dir, &self.node).await
+ }
+
+ async fn installation_test_binary(
+ &self,
+ container_dir: PathBuf,
+ ) -> Option<LanguageServerBinary> {
+ get_cached_server_binary(container_dir, &self.node).await
+ }
+
+ async fn initialization_options(&self) -> Option<serde_json::Value> {
+ Some(json!({
+ "provideFormatter": true
+ }))
+ }
+}
+
+async fn get_cached_server_binary(
+ container_dir: PathBuf,
+ node: &NodeRuntime,
+) -> Option<LanguageServerBinary> {
+ (|| async move {
+ let mut last_version_dir = None;
+ let mut entries = fs::read_dir(&container_dir).await?;
+ while let Some(entry) = entries.next().await {
+ let entry = entry?;
+ if entry.file_type().await?.is_dir() {
+ last_version_dir = Some(entry.path());
+ }
+ }
+ let last_version_dir = last_version_dir.ok_or_else(|| anyhow!("no cached binary"))?;
+ let server_path = last_version_dir.join(SERVER_PATH);
+ if server_path.exists() {
+ Ok(LanguageServerBinary {
+ path: node.binary_path().await?,
+ arguments: server_binary_arguments(&server_path),
+ })
+ } else {
+ Err(anyhow!(
+ "missing executable in directory {:?}",
+ last_version_dir
+ ))
+ }
+ })()
+ .await
+ .log_err()
+}
@@ -0,0 +1,18 @@
+name = "Svelte"
+path_suffixes = ["svelte"]
+line_comment = "// "
+autoclose_before = ";:.,=}])>"
+brackets = [
+ { start = "{", end = "}", close = true, newline = true },
+ { start = "[", end = "]", close = true, newline = true },
+ { start = "(", end = ")", close = true, newline = true },
+ { start = "<", end = ">", close = false, newline = true, not_in = ["string", "comment"] },
+ { start = "\"", end = "\"", close = true, newline = false, not_in = ["string"] },
+ { start = "'", end = "'", close = true, newline = false, not_in = ["string", "comment"] },
+ { start = "`", end = "`", close = true, newline = false, not_in = ["string"] },
+ { start = "/*", end = " */", close = true, newline = false, not_in = ["string", "comment"] },
+]
+
+[overrides.element]
+line_comment = { remove = true }
+block_comment = ["{/* ", " */}"]
@@ -0,0 +1,9 @@
+[
+ (style_element)
+ (script_element)
+ (element)
+ (if_statement)
+ (else_statement)
+ (each_statement)
+ (await_statement)
+] @fold
@@ -0,0 +1,68 @@
+; Special identifiers
+;--------------------
+[
+ "<"
+ ">"
+ "</"
+ "/>"
+ "#"
+ ":"
+ "/"
+ "@"
+] @tag.delimiter
+
+[
+ "{"
+ "}"
+] @punctuation.bracket
+
+[
+ (special_block_keyword)
+ (then)
+ (as)
+] @keyword
+
+[
+ (text)
+ (raw_text_expr)
+] @none
+
+[
+ (attribute_value)
+ (quoted_attribute_value)
+] @string
+
+(tag_name) @tag
+(attribute_name) @property
+(erroneous_end_tag_name) @error
+(comment) @comment
+
+((attribute
+ (attribute_name) @_attr
+ (quoted_attribute_value (attribute_value) @text.uri))
+ (#match? @_attr "^(href|src)$"))
+
+; TODO:
+
+((element (start_tag (tag_name) @_tag) (text) @text.uri)
+ (#eq? @_tag "a"))
+
+((element (start_tag (tag_name) @_tag) (text) @text.literal)
+ (#match? @_tag "^(code|kbd)$"))
+
+((element (start_tag (tag_name) @_tag) (text) @text.underline)
+ (#eq? @_tag "u"))
+
+((element (start_tag (tag_name) @_tag) (text) @text.strike)
+ (#match? @_tag "^(s|del)$"))
+
+((element (start_tag (tag_name) @_tag) (text) @text.emphasis)
+ (#match? @_tag "^(em|i)$"))
+
+((element (start_tag (tag_name) @_tag) (text) @text.strong)
+ (#match? @_tag "^(strong|b)$"))
+
+((element (start_tag (tag_name) @_tag) (text) @text.title)
+ (#match? @_tag "^(h[0-9]|title)$"))
+
+"=" @operator
@@ -0,0 +1,20 @@
+[
+ (element)
+ (if_statement)
+ (each_statement)
+ (await_statement)
+ (script_element)
+ (style_element)
+] @indent
+
+[
+ (end_tag)
+ (else_statement)
+ (if_end_expr)
+ (each_end_expr)
+ (await_end_expr)
+ ">"
+ "/>"
+] @branch
+
+(comment) @ignore
@@ -0,0 +1,9 @@
+; injections.scm
+; --------------
+(script_element
+ (raw_text) @content
+ (#set! "language" "javascript"))
+
+(style_element
+ (raw_text) @content
+ (#set! "language" "css"))