Add zig support

This commit is contained in:
Allan Calix 2024-01-24 20:07:18 -08:00
parent 37647a67a7
commit e5b71cc6ac
No known key found for this signature in database
10 changed files with 430 additions and 0 deletions

10
Cargo.lock generated
View File

@ -8716,6 +8716,15 @@ dependencies = [
"tree-sitter",
]
[[package]]
name = "tree-sitter-zig"
version = "0.0.1"
source = "git+https://github.com/maxxnino/tree-sitter-zig?rev=0d08703e4c3f426ec61695d7617415fff97029bd#0d08703e4c3f426ec61695d7617415fff97029bd"
dependencies = [
"cc",
"tree-sitter",
]
[[package]]
name = "try-lock"
version = "0.2.4"
@ -9812,6 +9821,7 @@ dependencies = [
"tree-sitter-uiua",
"tree-sitter-vue",
"tree-sitter-yaml",
"tree-sitter-zig",
"unindent",
"url",
"urlencoding",

View File

@ -161,6 +161,7 @@ tree-sitter-nix = { git = "https://github.com/nix-community/tree-sitter-nix", re
tree-sitter-nu = { git = "https://github.com/nushell/tree-sitter-nu", rev = "26bbaecda0039df4067861ab38ea8ea169f7f5aa"}
tree-sitter-vue = {git = "https://github.com/zed-industries/tree-sitter-vue", rev = "6608d9d60c386f19d80af7d8132322fa11199c42"}
tree-sitter-uiua = {git = "https://github.com/shnarazk/tree-sitter-uiua", rev = "9260f11be5900beda4ee6d1a24ab8ddfaf5a19b2"}
tree-sitter-zig = { git = "https://github.com/maxxnino/tree-sitter-zig", rev = "0d08703e4c3f426ec61695d7617415fff97029bd" }
[patch.crates-io]
tree-sitter = { git = "https://github.com/tree-sitter/tree-sitter", rev = "31c40449749c4263a91a43593831b82229049a4c" }

View File

@ -142,6 +142,7 @@ tree-sitter-nix.workspace = true
tree-sitter-nu.workspace = true
tree-sitter-vue.workspace = true
tree-sitter-uiua.workspace = true
tree-sitter-zig.workspace = true
url = "2.2"
urlencoding = "2.1.2"

View File

@ -31,6 +31,7 @@ mod typescript;
mod uiua;
mod vue;
mod yaml;
mod zig;
// 1. Add tree-sitter-{language} parser to zed crate
// 2. Create a language directory in zed/crates/zed/src/languages and add the language to init function below
@ -112,6 +113,11 @@ pub fn init(
tree_sitter_go::language(),
vec![Arc::new(go::GoLspAdapter)],
);
language(
"zig",
tree_sitter_zig::language(),
vec![Arc::new(zig::ZlsAdapter)],
);
language(
"heex",
tree_sitter_heex::language(),

View File

@ -0,0 +1,125 @@
use anyhow::{anyhow, Context, Result};
use async_compression::futures::bufread::GzipDecoder;
use async_tar::Archive;
use async_trait::async_trait;
use futures::{io::BufReader, StreamExt};
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
use lsp::LanguageServerBinary;
use smol::fs;
use std::env::consts::ARCH;
use std::{any::Any, path::PathBuf};
use util::async_maybe;
use util::github::latest_github_release;
use util::{github::GitHubLspBinaryVersion, ResultExt};
pub struct ZlsAdapter;
#[async_trait]
impl LspAdapter for ZlsAdapter {
fn name(&self) -> LanguageServerName {
LanguageServerName("zls".into())
}
fn short_name(&self) -> &'static str {
"zls"
}
async fn fetch_latest_server_version(
&self,
delegate: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>> {
let release = latest_github_release("zigtools/zls", false, delegate.http_client()).await?;
let asset_name = format!("zls-{}-macos.tar.gz", ARCH);
let asset = release
.assets
.iter()
.find(|asset| asset.name == asset_name)
.ok_or_else(|| anyhow!("no asset found matching {:?}", asset_name))?;
let version = GitHubLspBinaryVersion {
name: release.name,
url: asset.browser_download_url.clone(),
};
Ok(Box::new(version) as Box<_>)
}
async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
container_dir: PathBuf,
delegate: &dyn LspAdapterDelegate,
) -> Result<LanguageServerBinary> {
let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
let binary_path = container_dir.join("bin/zls");
if fs::metadata(&binary_path).await.is_err() {
let mut response = delegate
.http_client()
.get(&version.url, Default::default(), true)
.await
.context("error downloading release")?;
let decompressed_bytes = GzipDecoder::new(BufReader::new(response.body_mut()));
let archive = Archive::new(decompressed_bytes);
archive.unpack(container_dir).await?;
}
fs::set_permissions(
&binary_path,
<fs::Permissions as fs::unix::PermissionsExt>::from_mode(0o755),
)
.await?;
Ok(LanguageServerBinary {
path: binary_path,
arguments: vec![],
})
}
async fn cached_server_binary(
&self,
container_dir: PathBuf,
_: &dyn LspAdapterDelegate,
) -> Option<LanguageServerBinary> {
get_cached_server_binary(container_dir).await
}
async fn installation_test_binary(
&self,
container_dir: PathBuf,
) -> Option<LanguageServerBinary> {
get_cached_server_binary(container_dir)
.await
.map(|mut binary| {
binary.arguments = vec!["--help".into()];
binary
})
}
}
async fn get_cached_server_binary(container_dir: PathBuf) -> Option<LanguageServerBinary> {
async_maybe!({
let mut last_binary_path = 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_file()
&& entry
.file_name()
.to_str()
.map_or(false, |name| name == "zls")
{
last_binary_path = Some(entry.path());
}
}
if let Some(path) = last_binary_path {
Ok(LanguageServerBinary {
path,
arguments: Vec::new(),
})
} else {
Err(anyhow!("no cached binary"))
}
})
.await
.log_err()
}

View File

@ -0,0 +1,10 @@
name = "Zig"
path_suffixes = ["zig"]
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 = true, newline = true },
]

View File

@ -0,0 +1,16 @@
[
(Block)
(ContainerDecl)
(SwitchExpr)
(InitList)
(AsmExpr)
(ErrorSetDecl)
(LINESTRING)
(
[
(IfPrefix)
(WhilePrefix)
(ForPrefix)
]
)
] @fold

View File

@ -0,0 +1,234 @@
[
(container_doc_comment)
(doc_comment)
(line_comment)
] @comment
[
variable: (IDENTIFIER)
variable_type_function: (IDENTIFIER)
] @variable
parameter: (IDENTIFIER) @parameter
[
field_member: (IDENTIFIER)
field_access: (IDENTIFIER)
] @field
;; assume TitleCase is a type
(
[
variable_type_function: (IDENTIFIER)
field_access: (IDENTIFIER)
parameter: (IDENTIFIER)
] @type
(#match? @type "^[A-Z]([a-z]+[A-Za-z0-9]*)*$")
)
;; assume camelCase is a function
(
[
variable_type_function: (IDENTIFIER)
field_access: (IDENTIFIER)
parameter: (IDENTIFIER)
] @function
(#match? @function "^[a-z]+([A-Z][a-z0-9]*)+$")
)
;; assume all CAPS_1 is a constant
(
[
variable_type_function: (IDENTIFIER)
field_access: (IDENTIFIER)
] @constant
(#match? @constant "^[A-Z][A-Z_0-9]+$")
)
[
function_call: (IDENTIFIER)
function: (IDENTIFIER)
] @function
exception: "!" @exception
(
(IDENTIFIER) @variable.builtin
(#eq? @variable.builtin "_")
)
(PtrTypeStart "c" @variable.builtin)
(
(ContainerDeclType
[
(ErrorUnionExpr)
"enum"
]
)
(ContainerField (IDENTIFIER) @constant)
)
field_constant: (IDENTIFIER) @constant
(BUILTINIDENTIFIER) @keyword
; No idea why this doesnt work
; ((BUILTINIDENTIFIER) @include
; (#any-of? @include "@import" "@cImport"))
(INTEGER) @number
(FLOAT) @float
[
"true"
"false"
] @boolean
[
(LINESTRING)
(STRINGLITERALSINGLE)
] @string
(CHAR_LITERAL) @character
(EscapeSequence) @string.escape
(FormatSequence) @string.special
(BreakLabel (IDENTIFIER) @label)
(BlockLabel (IDENTIFIER) @label)
[
"asm"
"defer"
"errdefer"
"test"
"struct"
"union"
"enum"
"opaque"
"error"
] @keyword
[
"async"
"await"
"suspend"
"nosuspend"
"resume"
] @keyword.coroutine
[
"fn"
] @keyword.function
[
"and"
"or"
"orelse"
] @keyword.operator
[
"return"
] @keyword.return
[
"if"
"else"
"switch"
] @conditional
[
"for"
"while"
"break"
"continue"
] @keyword
[
"usingnamespace"
] @include
[
"try"
"catch"
] @keyword
[
"anytype"
(BuildinTypeExpr)
] @type.builtin
[
"const"
"var"
"volatile"
"allowzero"
"noalias"
] @type.qualifier
[
"addrspace"
"align"
"callconv"
"linksection"
] @storageclass
[
"comptime"
"export"
"extern"
"inline"
"noinline"
"packed"
"pub"
"threadlocal"
] @attribute
[
"null"
"unreachable"
"undefined"
] @constant.builtin
[
(CompareOp)
(BitwiseOp)
(BitShiftOp)
(AdditionOp)
(AssignOp)
(MultiplyOp)
(PrefixOp)
"*"
"**"
"->"
".?"
".*"
"?"
] @operator
[
";"
"."
","
":"
] @punctuation.delimiter
[
".."
"..."
] @punctuation.special
[
"["
"]"
"("
")"
"{"
"}"
(Payload "|")
(PtrPayload "|")
(PtrIndexPayload "|")
] @punctuation.bracket
; Error
(ERROR) @error

View File

@ -0,0 +1,22 @@
[
(Block)
(ContainerDecl)
(SwitchExpr)
(InitList)
] @indent
[
"("
")"
"["
"]"
"{"
"}"
] @branch
[
(line_comment)
(container_doc_comment)
(doc_comment)
(LINESTRING)
] @ignore

View File

@ -0,0 +1,5 @@
[
(container_doc_comment)
(doc_comment)
(line_comment)
] @comment