Add svelte language server

Add svelte tree sitter
Add svelte config file
Add svelte highlighting
This commit is contained in:
Mikayla Maki 2023-07-13 21:43:53 -07:00
parent 415b8f0147
commit 1424a7a56a
No known key found for this signature in database
9 changed files with 268 additions and 1 deletions

10
Cargo.lock generated
View file

@ -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",

View file

@ -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"

View file

@ -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()))],
);
}

View file

@ -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()
}

View file

@ -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 = ["{/* ", " */}"]

View file

@ -0,0 +1,9 @@
[
(style_element)
(script_element)
(element)
(if_statement)
(else_statement)
(each_statement)
(await_statement)
] @fold

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,9 @@
; injections.scm
; --------------
(script_element
(raw_text) @content
(#set! "language" "javascript"))
(style_element
(raw_text) @content
(#set! "language" "css"))