Merge pull request #2131 from zed-industries/lua

Add lua syntax highlighting and lsp support
This commit is contained in:
Kay Simmons 2023-02-06 15:40:03 -08:00 committed by GitHub
commit 2d6219ebe2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 452 additions and 3 deletions

109
Cargo.lock generated
View File

@ -259,6 +259,21 @@ dependencies = [
"futures-lite",
]
[[package]]
name = "async-global-executor"
version = "2.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1b6f5d7df27bd294849f8eec66ecfc63d11814df7a4f5d74168a2394467b776"
dependencies = [
"async-channel",
"async-executor",
"async-io",
"async-lock",
"blocking",
"futures-lite",
"once_cell",
]
[[package]]
name = "async-io"
version = "1.12.0"
@ -350,6 +365,32 @@ dependencies = [
"syn",
]
[[package]]
name = "async-std"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62565bb4402e926b29953c785397c6dc0391b7b446e45008b0049eb43cec6f5d"
dependencies = [
"async-channel",
"async-global-executor",
"async-io",
"async-lock",
"crossbeam-utils 0.8.14",
"futures-channel",
"futures-core",
"futures-io",
"futures-lite",
"gloo-timers",
"kv-log-macro",
"log",
"memchr",
"once_cell",
"pin-project-lite 0.2.9",
"pin-utils",
"slab",
"wasm-bindgen-futures",
]
[[package]]
name = "async-stream"
version = "0.3.3"
@ -371,6 +412,20 @@ dependencies = [
"syn",
]
[[package]]
name = "async-tar"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c49359998a76e32ef6e870dbc079ebad8f1e53e8441c5dd39d27b44493fe331"
dependencies = [
"async-std",
"filetime",
"libc",
"pin-project",
"redox_syscall",
"xattr",
]
[[package]]
name = "async-task"
version = "4.0.3"
@ -2080,6 +2135,18 @@ dependencies = [
"workspace",
]
[[package]]
name = "filetime"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e884668cd0c7480504233e951174ddc3b382f7c2666e3b7310b5c4e7b0c37f9"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall",
"windows-sys 0.42.0",
]
[[package]]
name = "fixedbitset"
version = "0.4.2"
@ -2528,6 +2595,18 @@ dependencies = [
"regex",
]
[[package]]
name = "gloo-timers"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c"
dependencies = [
"futures-channel",
"futures-core",
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "go_to_line"
version = "0.1.0"
@ -3144,6 +3223,15 @@ dependencies = [
"arrayvec 0.7.2",
]
[[package]]
name = "kv-log-macro"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f"
dependencies = [
"log",
]
[[package]]
name = "language"
version = "0.1.0"
@ -7017,6 +7105,16 @@ dependencies = [
"tree-sitter",
]
[[package]]
name = "tree-sitter-lua"
version = "0.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d489873fd1a2fa6d5f04930bfc5c081c96f0c038c1437104518b5b842c69b282"
dependencies = [
"cc",
"tree-sitter",
]
[[package]]
name = "tree-sitter-markdown"
version = "0.0.1"
@ -8194,6 +8292,15 @@ dependencies = [
"winapi-build",
]
[[package]]
name = "xattr"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d1526bbe5aaeb5eb06885f4d987bcdfa5e23187055de9b83fe00156a821fabc"
dependencies = [
"libc",
]
[[package]]
name = "xml-rs"
version = "0.8.4"
@ -8236,6 +8343,7 @@ dependencies = [
"assets",
"async-compression",
"async-recursion 0.3.2",
"async-tar",
"async-trait",
"auto_update",
"backtrace",
@ -8313,6 +8421,7 @@ dependencies = [
"tree-sitter-go",
"tree-sitter-html",
"tree-sitter-json 0.20.0",
"tree-sitter-lua",
"tree-sitter-markdown",
"tree-sitter-python",
"tree-sitter-racket",

View File

@ -1,3 +1,4 @@
use log::warn;
pub use lsp_types::request::*;
pub use lsp_types::*;
@ -220,10 +221,10 @@ impl LanguageServer {
}
}
} else {
return Err(anyhow!(
"failed to deserialize message:\n{}",
warn!(
"Failed to deserialize message:\n{}",
std::str::from_utf8(&buffer)?
));
);
}
// Don't starve the main thread when receiving lots of messages at once.

View File

@ -60,6 +60,7 @@ vim = { path = "../vim" }
workspace = { path = "../workspace" }
anyhow = "1.0.38"
async-compression = { version = "0.3", features = ["gzip", "futures-bufread"] }
async-tar = "0.4.2"
async-recursion = "0.3"
async-trait = "0.1"
backtrace = "0.3"
@ -109,6 +110,7 @@ tree-sitter-ruby = "0.20.0"
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-lua = "0.0.14"
url = "2.2"
urlencoding = "2.1.2"
uuid = { version = "1.1.2", features = ["v4"] }

View File

@ -10,6 +10,7 @@ mod html;
mod installation;
mod json;
mod language_plugin;
mod lua;
mod python;
mod ruby;
mod rust;
@ -122,6 +123,11 @@ pub fn init(languages: Arc<LanguageRegistry>) {
tree_sitter_racket::language(),
None, //
),
(
"lua",
tree_sitter_lua::language(),
Some(Box::new(lua::LuaLspAdapter)),
),
] {
languages.register(name, load_config(name), grammar, lsp_adapter, load_queries);
}

View File

@ -0,0 +1,108 @@
use std::{any::Any, env::consts, path::PathBuf, sync::Arc};
use anyhow::{anyhow, bail, Result};
use async_compression::futures::bufread::GzipDecoder;
use async_tar::Archive;
use async_trait::async_trait;
use client::http::HttpClient;
use futures::{io::BufReader, StreamExt};
use language::LanguageServerName;
use smol::fs;
use util::{async_iife, ResultExt};
use super::installation::{latest_github_release, GitHubLspBinaryVersion};
#[derive(Copy, Clone)]
pub struct LuaLspAdapter;
#[async_trait]
impl super::LspAdapter for LuaLspAdapter {
async fn name(&self) -> LanguageServerName {
LanguageServerName("lua-language-server".into())
}
async fn server_args(&self) -> Vec<String> {
vec![
"--logpath=~/lua-language-server.log".into(),
"--loglevel=trace".into(),
]
}
async fn fetch_latest_server_version(
&self,
http: Arc<dyn HttpClient>,
) -> Result<Box<dyn 'static + Send + Any>> {
let release = latest_github_release("LuaLS/lua-language-server", http).await?;
let version = release.name.clone();
let platform = match consts::ARCH {
"x86_64" => "x64",
"aarch64" => "arm64",
other => bail!("Running on unsupported platform: {other}"),
};
let asset_name = format!("lua-language-server-{version}-darwin-{platform}.tar.gz");
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.clone(),
url: asset.browser_download_url.clone(),
};
Ok(Box::new(version) as Box<_>)
}
async fn fetch_server_binary(
&self,
version: Box<dyn 'static + Send + Any>,
http: Arc<dyn HttpClient>,
container_dir: PathBuf,
) -> Result<PathBuf> {
let version = version.downcast::<GitHubLspBinaryVersion>().unwrap();
let binary_path = container_dir.join("bin/lua-language-server");
if fs::metadata(&binary_path).await.is_err() {
let mut response = http
.get(&version.url, Default::default(), true)
.await
.map_err(|err| anyhow!("error downloading release: {}", err))?;
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(binary_path)
}
async fn cached_server_binary(&self, container_dir: PathBuf) -> Option<PathBuf> {
async_iife!({
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 == "lua-language-server")
{
last_binary_path = Some(entry.path());
}
}
if let Some(path) = last_binary_path {
Ok(path)
} else {
Err(anyhow!("no cached binary"))
}
})
.await
.log_err()
}
}

View File

@ -0,0 +1,3 @@
("[" @open "]" @close)
("{" @open "}" @close)
("(" @open ")" @close)

View File

@ -0,0 +1,15 @@
name = "Lua"
path_suffixes = ["lua"]
line_comment = "-- "
autoclose_before = ",]}"
brackets = [
{ start = "{", end = "}", close = true, newline = true },
{ start = "[", end = "]", close = true, newline = true },
{ start = "\"", end = "\"", close = true, newline = false },
]
[overrides.string]
brackets = [
{ start = "{", end = "}", close = true, newline = true },
{ start = "[", end = "]", close = true, newline = true },
]

View File

@ -0,0 +1,192 @@
;; Keywords
"return" @keyword
[
"goto"
"in"
"local"
] @keyword
(break_statement) @keyword
(do_statement
[
"do"
"end"
] @keyword)
(while_statement
[
"while"
"do"
"end"
] @keyword)
(repeat_statement
[
"repeat"
"until"
] @keyword)
(if_statement
[
"if"
"elseif"
"else"
"then"
"end"
] @keyword)
(elseif_statement
[
"elseif"
"then"
"end"
] @keyword)
(else_statement
[
"else"
"end"
] @keyword)
(for_statement
[
"for"
"do"
"end"
] @keyword)
(function_declaration
[
"function"
"end"
] @keyword)
(function_definition
[
"function"
"end"
] @keyword)
;; Operators
[
"and"
"not"
"or"
] @operator
[
"+"
"-"
"*"
"/"
"%"
"^"
"#"
"=="
"~="
"<="
">="
"<"
">"
"="
"&"
"~"
"|"
"<<"
">>"
"//"
".."
] @operator
;; Punctuations
[
";"
":"
","
"."
] @punctuation.delimiter
;; Brackets
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket
;; Variables
(identifier) @variable
((identifier) @variable.special
(#eq? @variable.special "self"))
(variable_list
attribute: (attribute
(["<" ">"] @punctuation.bracket
(identifier) @attribute)))
;; Constants
((identifier) @constant
(#lua-match? @constant "^[A-Z][A-Z_0-9]*$"))
(vararg_expression) @constant
(nil) @constant.builtin
[
(false)
(true)
] @boolean
;; Tables
(field name: (identifier) @field)
(dot_index_expression field: (identifier) @field)
(table_constructor
[
"{"
"}"
] @constructor)
;; Functions
(parameters (identifier) @parameter)
(function_call name: (identifier) @function.call)
(function_declaration name: (identifier) @function)
(function_call name: (dot_index_expression field: (identifier) @function.call))
(function_declaration name: (dot_index_expression field: (identifier) @function))
(method_index_expression method: (identifier) @method)
(function_call
(identifier) @function.builtin
(#any-of? @function.builtin
;; built-in functions in Lua 5.1
"assert" "collectgarbage" "dofile" "error" "getfenv" "getmetatable" "ipairs"
"load" "loadfile" "loadstring" "module" "next" "pairs" "pcall" "print"
"rawequal" "rawget" "rawset" "require" "select" "setfenv" "setmetatable"
"tonumber" "tostring" "type" "unpack" "xpcall"))
;; Others
(comment) @comment
(hash_bang_line) @preproc
(number) @number
(string) @string

View File

@ -0,0 +1,10 @@
(if_statement "end" @end) @indent
(do_statement "end" @end) @indent
(while_statement "end" @end) @indent
(for_statement "end" @end) @indent
(repeat_statement "until" @end) @indent
(function_declaration "end" @end) @indent
(_ "[" "]" @end) @indent
(_ "{" "}" @end) @indent
(_ "(" ")" @end) @indent

View File

@ -0,0 +1,3 @@
(function_declaration
"function" @context
name: (_) @name) @item