Merge branch 'haskell-support' into add-haskell-grammar

This commit is contained in:
Pseudomata 2024-01-26 10:55:43 -05:00 committed by GitHub
commit 2b9ba46cb6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
146 changed files with 2847 additions and 1749 deletions

View file

@ -121,6 +121,7 @@ tree-sitter-elixir.workspace = true
tree-sitter-elm.workspace = true
tree-sitter-embedded-template.workspace = true
tree-sitter-glsl.workspace = true
tree-sitter-gleam.workspace = true
tree-sitter-go.workspace = true
tree-sitter-heex.workspace = true
tree-sitter-json.workspace = true
@ -142,6 +143,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

@ -7,11 +7,13 @@ use settings::Settings;
use std::{borrow::Cow, str, sync::Arc};
use util::{asset_str, paths::PLUGINS_DIR};
use self::elixir::ElixirSettings;
use self::{deno::DenoSettings, elixir::ElixirSettings};
mod c;
mod css;
mod deno;
mod elixir;
mod gleam;
mod go;
mod haskell;
mod html;
@ -30,6 +32,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
@ -51,6 +54,7 @@ pub fn init(
cx: &mut AppContext,
) {
ElixirSettings::register(cx);
DenoSettings::register(cx);
let language = |name, grammar, adapters| {
languages.register(name, load_config(name), grammar, adapters, load_queries)
@ -100,11 +104,21 @@ pub fn init(
),
}
language(
"gleam",
tree_sitter_gleam::language(),
vec![Arc::new(gleam::GleamLspAdapter)],
);
language(
"go",
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(),
@ -135,32 +149,59 @@ pub fn init(
vec![Arc::new(rust::RustLspAdapter)],
);
language("toml", tree_sitter_toml::language(), vec![]);
language(
"tsx",
tree_sitter_typescript::language_tsx(),
vec![
Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
],
);
language(
"typescript",
tree_sitter_typescript::language_typescript(),
vec![
Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
],
);
language(
"javascript",
tree_sitter_typescript::language_tsx(),
vec![
Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
],
);
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(
"javascript",
tree_sitter_typescript::language_tsx(),
vec![
Arc::new(deno::DenoLspAdapter::new()),
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
],
);
}
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())),
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
],
);
language(
"typescript",
tree_sitter_typescript::language_typescript(),
vec![
Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
],
);
language(
"javascript",
tree_sitter_typescript::language_tsx(),
vec![
Arc::new(typescript::TypeScriptLspAdapter::new(node_runtime.clone())),
Arc::new(typescript::EsLintLspAdapter::new(node_runtime.clone())),
Arc::new(tailwind::TailwindLspAdapter::new(node_runtime.clone())),
],
);
}
}
language("haskell", tree_sitter_haskell::language(), vec![]);
language(
"html",

View file

@ -1,6 +1,6 @@
name = "Shell Script"
path_suffixes = ["sh", "bash", "bashrc", "bash_profile", "bash_aliases", "bash_logout", "profile", "zsh", "zshrc", "zshenv", "zsh_profile", "zsh_aliases", "zsh_histfile", "zlogin", "zprofile"]
line_comment = "# "
line_comments = ["# "]
first_line_pattern = "^#!.*\\b(?:ba|z)?sh\\b"
brackets = [
{ start = "[", end = "]", close = true, newline = false },

View file

@ -15,7 +15,7 @@ pub struct CLspAdapter;
#[async_trait]
impl super::LspAdapter for CLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("clangd".into())
}

View file

@ -1,6 +1,6 @@
name = "C"
path_suffixes = ["c"]
line_comment = "// "
line_comments = ["// "]
autoclose_before = ";:.,=}])>"
brackets = [
{ start = "{", end = "}", close = true, newline = true },

View file

@ -1,6 +1,6 @@
name = "C++"
path_suffixes = ["cc", "cpp", "h", "hpp", "cxx", "hxx", "inl"]
line_comment = "// "
line_comments = ["// "]
autoclose_before = ";:.,=}])>"
brackets = [
{ start = "{", end = "}", close = true, newline = true },

View file

@ -33,7 +33,7 @@ impl CssLspAdapter {
#[async_trait]
impl LspAdapter for CssLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("vscode-css-language-server".into())
}
@ -91,7 +91,7 @@ impl LspAdapter for CssLspAdapter {
get_cached_server_binary(container_dir, &*self.node).await
}
async fn initialization_options(&self) -> Option<serde_json::Value> {
fn initialization_options(&self) -> Option<serde_json::Value> {
Some(json!({
"provideFormatter": true
}))

View file

@ -0,0 +1,223 @@
use anyhow::{anyhow, Context, Result};
use async_trait::async_trait;
use collections::HashMap;
use futures::StreamExt;
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
use lsp::{CodeActionKind, LanguageServerBinary};
use schemars::JsonSchema;
use serde_derive::{Deserialize, Serialize};
use serde_json::json;
use settings::Settings;
use smol::{fs, fs::File};
use std::{any::Any, env::consts, ffi::OsString, path::PathBuf, sync::Arc};
use util::{fs::remove_matching, github::latest_github_release};
use util::{github::GitHubLspBinaryVersion, ResultExt};
#[derive(Clone, Serialize, Deserialize, JsonSchema)]
pub struct DenoSettings {
pub enable: bool,
}
#[derive(Clone, Serialize, Default, Deserialize, JsonSchema)]
pub struct DenoSettingsContent {
enable: Option<bool>,
}
impl Settings for DenoSettings {
const KEY: Option<&'static str> = Some("deno");
type FileContent = DenoSettingsContent;
fn load(
default_value: &Self::FileContent,
user_values: &[&Self::FileContent],
_: &mut gpui::AppContext,
) -> Result<Self>
where
Self: Sized,
{
Self::load_via_json_merge(default_value, user_values)
}
}
fn deno_server_binary_arguments() -> Vec<OsString> {
vec!["lsp".into()]
}
pub struct DenoLspAdapter {}
impl DenoLspAdapter {
pub fn new() -> Self {
DenoLspAdapter {}
}
}
#[async_trait]
impl LspAdapter for DenoLspAdapter {
fn name(&self) -> LanguageServerName {
LanguageServerName("deno-language-server".into())
}
fn short_name(&self) -> &'static str {
"deno-ts"
}
async fn fetch_latest_server_version(
&self,
delegate: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>> {
let release = latest_github_release("denoland/deno", false, delegate.http_client()).await?;
let asset_name = format!("deno-{}-apple-darwin.zip", consts::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 zip_path = container_dir.join(format!("deno_{}.zip", version.name));
let version_dir = container_dir.join(format!("deno_{}", version.name));
let binary_path = version_dir.join("deno");
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 mut file = File::create(&zip_path).await?;
if !response.status().is_success() {
Err(anyhow!(
"download failed with status {}",
response.status().to_string()
))?;
}
futures::io::copy(response.body_mut(), &mut file).await?;
let unzip_status = smol::process::Command::new("unzip")
.current_dir(&container_dir)
.arg(&zip_path)
.arg("-d")
.arg(&version_dir)
.output()
.await?
.status;
if !unzip_status.success() {
Err(anyhow!("failed to unzip deno archive"))?;
}
remove_matching(&container_dir, |entry| entry != version_dir).await;
}
Ok(LanguageServerBinary {
path: binary_path,
arguments: deno_server_binary_arguments(),
})
}
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
}
fn code_action_kinds(&self) -> Option<Vec<CodeActionKind>> {
Some(vec![
CodeActionKind::QUICKFIX,
CodeActionKind::REFACTOR,
CodeActionKind::REFACTOR_EXTRACT,
CodeActionKind::SOURCE,
])
}
async fn label_for_completion(
&self,
item: &lsp::CompletionItem,
language: &Arc<language::Language>,
) -> Option<language::CodeLabel> {
use lsp::CompletionItemKind as Kind;
let len = item.label.len();
let grammar = language.grammar()?;
let highlight_id = match item.kind? {
Kind::CLASS | Kind::INTERFACE => grammar.highlight_id_for_name("type"),
Kind::CONSTRUCTOR => grammar.highlight_id_for_name("type"),
Kind::CONSTANT => grammar.highlight_id_for_name("constant"),
Kind::FUNCTION | Kind::METHOD => grammar.highlight_id_for_name("function"),
Kind::PROPERTY | Kind::FIELD => grammar.highlight_id_for_name("property"),
_ => None,
}?;
let text = match &item.detail {
Some(detail) => format!("{} {}", item.label, detail),
None => item.label.clone(),
};
Some(language::CodeLabel {
text,
runs: vec![(0..len, highlight_id)],
filter_range: 0..len,
})
}
fn initialization_options(&self) -> Option<serde_json::Value> {
Some(json!({
"provideFormatter": true,
}))
}
fn language_ids(&self) -> HashMap<String, String> {
HashMap::from_iter([
("TypeScript".into(), "typescript".into()),
("JavaScript".into(), "javascript".into()),
("TSX".into(), "typescriptreact".into()),
])
}
}
async fn get_cached_server_binary(container_dir: PathBuf) -> Option<LanguageServerBinary> {
(|| async move {
let mut last = None;
let mut entries = fs::read_dir(&container_dir).await?;
while let Some(entry) = entries.next().await {
last = Some(entry?.path());
}
match last {
Some(path) if path.is_dir() => {
let binary = path.join("deno");
if fs::metadata(&binary).await.is_ok() {
return Ok(LanguageServerBinary {
path: binary,
arguments: deno_server_binary_arguments(),
});
}
}
_ => {}
}
Err(anyhow!("no cached binary"))
})()
.await
.log_err()
}

View file

@ -67,7 +67,7 @@ pub struct ElixirLspAdapter;
#[async_trait]
impl LspAdapter for ElixirLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("elixir-ls".into())
}
@ -301,7 +301,7 @@ pub struct NextLspAdapter;
#[async_trait]
impl LspAdapter for NextLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("next-ls".into())
}
@ -452,7 +452,7 @@ pub struct LocalLspAdapter {
#[async_trait]
impl LspAdapter for LocalLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("local-ls".into())
}

View file

@ -1,6 +1,6 @@
name = "Elixir"
path_suffixes = ["ex", "exs"]
line_comment = "# "
line_comments = ["# "]
autoclose_before = ";:.,=}])>"
brackets = [
{ start = "{", end = "}", close = true, newline = true },

View file

@ -1,6 +1,6 @@
name = "Elm"
path_suffixes = ["elm"]
line_comment = "-- "
line_comments = ["-- "]
block_comment = ["{- ", " -}"]
brackets = [
{ start = "{", end = "}", close = true, newline = true },

View file

@ -0,0 +1,118 @@
use std::any::Any;
use std::ffi::OsString;
use std::path::PathBuf;
use anyhow::{anyhow, Result};
use async_compression::futures::bufread::GzipDecoder;
use async_tar::Archive;
use async_trait::async_trait;
use futures::io::BufReader;
use futures::StreamExt;
use language::{LanguageServerName, LspAdapter, LspAdapterDelegate};
use lsp::LanguageServerBinary;
use smol::fs;
use util::github::{latest_github_release, GitHubLspBinaryVersion};
use util::{async_maybe, ResultExt};
fn server_binary_arguments() -> Vec<OsString> {
vec!["lsp".into()]
}
pub struct GleamLspAdapter;
#[async_trait]
impl LspAdapter for GleamLspAdapter {
fn name(&self) -> LanguageServerName {
LanguageServerName("gleam".into())
}
fn short_name(&self) -> &'static str {
"gleam"
}
async fn fetch_latest_server_version(
&self,
delegate: &dyn LspAdapterDelegate,
) -> Result<Box<dyn 'static + Send + Any>> {
let release =
latest_github_release("gleam-lang/gleam", false, delegate.http_client()).await?;
let asset_name = format!(
"gleam-{version}-{arch}-apple-darwin.tar.gz",
version = release.name,
arch = std::env::consts::ARCH
);
let asset = release
.assets
.iter()
.find(|asset| asset.name == asset_name)
.ok_or_else(|| anyhow!("no asset found matching {:?}", asset_name))?;
Ok(Box::new(GitHubLspBinaryVersion {
name: release.name,
url: asset.browser_download_url.clone(),
}))
}
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("gleam");
if fs::metadata(&binary_path).await.is_err() {
let mut response = delegate
.http_client()
.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?;
}
Ok(LanguageServerBinary {
path: binary_path,
arguments: server_binary_arguments(),
})
}
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!["--version".into()];
binary
})
}
}
async fn get_cached_server_binary(container_dir: PathBuf) -> Option<LanguageServerBinary> {
async_maybe!({
let mut last = None;
let mut entries = fs::read_dir(&container_dir).await?;
while let Some(entry) = entries.next().await {
last = Some(entry?.path());
}
anyhow::Ok(LanguageServerBinary {
path: last.ok_or_else(|| anyhow!("no cached binary"))?,
arguments: server_binary_arguments(),
})
})
.await
.log_err()
}

View file

@ -0,0 +1,10 @@
name = "Gleam"
path_suffixes = ["gleam"]
line_comments = ["// ", "/// "]
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 = false, not_in = ["string", "comment"] },
]

View file

@ -0,0 +1,130 @@
; Comments
(module_comment) @comment
(statement_comment) @comment
(comment) @comment
; Constants
(constant
name: (identifier) @constant)
; Modules
(module) @module
(import alias: (identifier) @module)
(remote_type_identifier
module: (identifier) @module)
(remote_constructor_name
module: (identifier) @module)
((field_access
record: (identifier) @module
field: (label) @function)
(#is-not? local))
; Functions
(unqualified_import (identifier) @function)
(unqualified_import "type" (type_identifier) @type)
(unqualified_import (type_identifier) @constructor)
(function
name: (identifier) @function)
(external_function
name: (identifier) @function)
(function_parameter
name: (identifier) @variable.parameter)
((function_call
function: (identifier) @function)
(#is-not? local))
((binary_expression
operator: "|>"
right: (identifier) @function)
(#is-not? local))
; "Properties"
; Assumed to be intended to refer to a name for a field; something that comes
; before ":" or after "."
; e.g. record field names, tuple indices, names for named arguments, etc
(label) @property
(tuple_access
index: (integer) @property)
; Attributes
(attribute
"@" @attribute
name: (identifier) @attribute)
(attribute_value (identifier) @constant)
; Type names
(remote_type_identifier) @type
(type_identifier) @type
; Data constructors
(constructor_name) @constructor
; Literals
(string) @string
((escape_sequence) @warning
; Deprecated in v0.33.0-rc2:
(#eq? @warning "\\e"))
(escape_sequence) @string.escape
(bit_string_segment_option) @function.builtin
(integer) @number
(float) @number
; Reserved identifiers
; TODO: when tree-sitter supports `#any-of?` in the Rust bindings,
; refactor this to use `#any-of?` rather than `#match?`
((identifier) @warning
(#match? @warning "^(auto|delegate|derive|else|implement|macro|test|echo)$"))
; Variables
(identifier) @variable
(discard) @comment.unused
; Keywords
[
(visibility_modifier) ; "pub"
(opacity_modifier) ; "opaque"
"as"
"assert"
"case"
"const"
; DEPRECATED: 'external' was removed in v0.30.
"external"
"fn"
"if"
"import"
"let"
"panic"
"todo"
"type"
"use"
] @keyword
; Operators
(binary_expression
operator: _ @operator)
(boolean_negation "!" @operator)
(integer_negation "-" @operator)
; Punctuation
[
"("
")"
"["
"]"
"{"
"}"
"<<"
">>"
] @punctuation.bracket
[
"."
","
;; Controversial -- maybe some are operators?
":"
"#"
"="
"->"
".."
"-"
"<-"
] @punctuation.delimiter

View file

@ -0,0 +1,4 @@
(function
(visibility_modifier)? @context
"fn" @context
name: (_) @name) @item

View file

@ -1,6 +1,6 @@
name = "GLSL"
path_suffixes = ["vert", "frag", "tesc", "tese", "geom", "comp"]
line_comment = "// "
line_comments = ["// "]
block_comment = ["/* ", " */"]
brackets = [
{ start = "{", end = "}", close = true, newline = true },

View file

@ -33,7 +33,7 @@ lazy_static! {
#[async_trait]
impl super::LspAdapter for GoLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("gopls".into())
}

View file

@ -1,6 +1,6 @@
name = "Go"
path_suffixes = ["go"]
line_comment = "// "
line_comments = ["// "]
autoclose_before = ";:.,=}])>"
brackets = [
{ start = "{", end = "}", close = true, newline = true },

View file

@ -33,7 +33,7 @@ impl HtmlLspAdapter {
#[async_trait]
impl LspAdapter for HtmlLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("vscode-html-language-server".into())
}
@ -91,7 +91,7 @@ impl LspAdapter for HtmlLspAdapter {
get_cached_server_binary(container_dir, &*self.node).await
}
async fn initialization_options(&self) -> Option<serde_json::Value> {
fn initialization_options(&self) -> Option<serde_json::Value> {
Some(json!({
"provideFormatter": true
}))

View file

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

View file

@ -1,7 +1,7 @@
name = "JavaScript"
path_suffixes = ["js", "jsx", "mjs", "cjs"]
first_line_pattern = '^#!.*\bnode\b'
line_comment = "// "
line_comments = ["// "]
autoclose_before = ";:.,=}])>"
brackets = [
{ start = "{", end = "}", close = true, newline = true },
@ -18,7 +18,7 @@ scope_opt_in_language_servers = ["tailwindcss-language-server"]
prettier_parser_name = "babel"
[overrides.element]
line_comment = { remove = true }
line_comments = { remove = true }
block_comment = ["{/* ", " */}"]
[overrides.string]

View file

@ -38,7 +38,7 @@ impl JsonLspAdapter {
#[async_trait]
impl LspAdapter for JsonLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("json-language-server".into())
}
@ -96,7 +96,7 @@ impl LspAdapter for JsonLspAdapter {
get_cached_server_binary(container_dir, &*self.node).await
}
async fn initialization_options(&self) -> Option<serde_json::Value> {
fn initialization_options(&self) -> Option<serde_json::Value> {
Some(json!({
"provideFormatter": true
}))
@ -140,7 +140,7 @@ impl LspAdapter for JsonLspAdapter {
})
}
async fn language_ids(&self) -> HashMap<String, String> {
fn language_ids(&self) -> HashMap<String, String> {
[("JSON".into(), "jsonc".into())].into_iter().collect()
}
}

View file

@ -1,6 +1,6 @@
name = "JSON"
path_suffixes = ["json"]
line_comment = "// "
line_comments = ["// "]
autoclose_before = ",]}"
brackets = [
{ start = "{", end = "}", close = true, newline = true },

View file

@ -18,7 +18,7 @@ pub struct LuaLspAdapter;
#[async_trait]
impl super::LspAdapter for LuaLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("lua-language-server".into())
}

View file

@ -1,6 +1,6 @@
name = "Lua"
path_suffixes = ["lua"]
line_comment = "-- "
line_comments = ["-- "]
autoclose_before = ",]}"
brackets = [
{ start = "{", end = "}", close = true, newline = true },

View file

@ -1,6 +1,6 @@
name = "Nix"
path_suffixes = ["nix"]
line_comment = "# "
line_comments = ["# "]
block_comment = ["/* ", " */"]
autoclose_before = ";:.,=}])>` \n\t\""
brackets = [

View file

@ -8,7 +8,7 @@ pub struct NuLanguageServer;
#[async_trait]
impl LspAdapter for NuLanguageServer {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("nu".into())
}

View file

@ -1,6 +1,6 @@
name = "Nu"
path_suffixes = ["nu"]
line_comment = "# "
line_comments = ["# "]
autoclose_before = ";:.,=}])>` \n\t\""
brackets = [
{ start = "{", end = "}", close = true, newline = true },

View file

@ -36,7 +36,7 @@ impl IntelephenseLspAdapter {
#[async_trait]
impl LspAdapter for IntelephenseLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("intelephense".into())
}
@ -96,10 +96,10 @@ impl LspAdapter for IntelephenseLspAdapter {
None
}
async fn initialization_options(&self) -> Option<serde_json::Value> {
fn initialization_options(&self) -> Option<serde_json::Value> {
None
}
async fn language_ids(&self) -> HashMap<String, String> {
fn language_ids(&self) -> HashMap<String, String> {
HashMap::from_iter([("PHP".into(), "php".into())])
}
}

View file

@ -1,7 +1,7 @@
name = "PHP"
path_suffixes = ["php"]
first_line_pattern = '^#!.*php'
line_comment = "// "
line_comments = ["// "]
autoclose_before = ";:.,=}])>"
brackets = [
{ start = "{", end = "}", close = true, newline = true },

View file

@ -30,7 +30,7 @@ impl PythonLspAdapter {
#[async_trait]
impl LspAdapter for PythonLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("pyright".into())
}

View file

@ -1,7 +1,7 @@
name = "Python"
path_suffixes = ["py", "pyi", "mpy"]
first_line_pattern = '^#!.*\bpython[0-9.]*\b'
line_comment = "# "
line_comments = ["# "]
autoclose_before = ";:.,=}])>"
brackets = [
{ start = "{", end = "}", close = true, newline = true },

View file

@ -1,6 +1,6 @@
name = "Racket"
path_suffixes = ["rkt"]
line_comment = "; "
line_comments = ["; "]
autoclose_before = "])"
brackets = [
{ start = "[", end = "]", close = true, newline = false },

View file

@ -8,7 +8,7 @@ pub struct RubyLanguageServer;
#[async_trait]
impl LspAdapter for RubyLanguageServer {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("solargraph".into())
}

View file

@ -1,7 +1,7 @@
name = "Ruby"
path_suffixes = ["rb", "Gemfile"]
first_line_pattern = '^#!.*\bruby\b'
line_comment = "# "
line_comments = ["# "]
autoclose_before = ";:.,=}])>"
brackets = [
{ start = "{", end = "}", close = true, newline = true },

View file

@ -18,7 +18,7 @@ pub struct RustLspAdapter;
#[async_trait]
impl LspAdapter for RustLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("rust-analyzer".into())
}
@ -98,11 +98,11 @@ impl LspAdapter for RustLspAdapter {
})
}
async fn disk_based_diagnostic_sources(&self) -> Vec<String> {
fn disk_based_diagnostic_sources(&self) -> Vec<String> {
vec!["rustc".into()]
}
async fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
fn disk_based_diagnostics_progress_token(&self) -> Option<String> {
Some("rust-analyzer/flycheck".into())
}

View file

@ -1,6 +1,6 @@
name = "Rust"
path_suffixes = ["rs"]
line_comment = "// "
line_comments = ["// ", "/// ", "//! "]
autoclose_before = ";:.,=}])>"
brackets = [
{ start = "{", end = "}", close = true, newline = true },

View file

@ -1,6 +1,6 @@
name = "Scheme"
path_suffixes = ["scm", "ss"]
line_comment = "; "
line_comments = ["; "]
autoclose_before = "])"
brackets = [
{ start = "[", end = "]", close = true, newline = false },

View file

@ -32,7 +32,7 @@ impl SvelteLspAdapter {
#[async_trait]
impl LspAdapter for SvelteLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("svelte-language-server".into())
}
@ -90,7 +90,7 @@ impl LspAdapter for SvelteLspAdapter {
get_cached_server_binary(container_dir, &*self.node).await
}
async fn initialization_options(&self) -> Option<serde_json::Value> {
fn initialization_options(&self) -> Option<serde_json::Value> {
Some(json!({
"provideFormatter": true
}))

View file

@ -34,7 +34,7 @@ impl TailwindLspAdapter {
#[async_trait]
impl LspAdapter for TailwindLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("tailwindcss-language-server".into())
}
@ -92,7 +92,7 @@ impl LspAdapter for TailwindLspAdapter {
get_cached_server_binary(container_dir, &*self.node).await
}
async fn initialization_options(&self) -> Option<serde_json::Value> {
fn initialization_options(&self) -> Option<serde_json::Value> {
Some(json!({
"provideFormatter": true,
"userLanguages": {
@ -112,7 +112,7 @@ impl LspAdapter for TailwindLspAdapter {
})
}
async fn language_ids(&self) -> HashMap<String, String> {
fn language_ids(&self) -> HashMap<String, String> {
HashMap::from_iter([
("HTML".to_string(), "html".to_string()),
("CSS".to_string(), "css".to_string()),

View file

@ -1,6 +1,6 @@
name = "TOML"
path_suffixes = ["Cargo.lock", "toml"]
line_comment = "# "
line_comments = ["# "]
autoclose_before = ",]}"
brackets = [
{ start = "{", end = "}", close = true, newline = true },

View file

@ -1,6 +1,6 @@
name = "TSX"
path_suffixes = ["tsx"]
line_comment = "// "
line_comments = ["// "]
autoclose_before = ";:.,=}])>"
brackets = [
{ start = "{", end = "}", close = true, newline = true },
@ -17,7 +17,7 @@ scope_opt_in_language_servers = ["tailwindcss-language-server"]
prettier_parser_name = "typescript"
[overrides.element]
line_comment = { remove = true }
line_comments = { remove = true }
block_comment = ["{/* ", " */}"]
[overrides.string]

View file

@ -46,7 +46,7 @@ struct TypeScriptVersions {
#[async_trait]
impl LspAdapter for TypeScriptLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("typescript-language-server".into())
}
@ -150,7 +150,7 @@ impl LspAdapter for TypeScriptLspAdapter {
})
}
async fn initialization_options(&self) -> Option<serde_json::Value> {
fn initialization_options(&self) -> Option<serde_json::Value> {
Some(json!({
"provideFormatter": true,
"tsserver": {
@ -159,7 +159,7 @@ impl LspAdapter for TypeScriptLspAdapter {
}))
}
async fn language_ids(&self) -> HashMap<String, String> {
fn language_ids(&self) -> HashMap<String, String> {
HashMap::from_iter([
("TypeScript".into(), "typescript".into()),
("JavaScript".into(), "javascript".into()),
@ -227,7 +227,7 @@ impl LspAdapter for EsLintLspAdapter {
})
}
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("eslint".into())
}
@ -315,7 +315,7 @@ impl LspAdapter for EsLintLspAdapter {
None
}
async fn initialization_options(&self) -> Option<serde_json::Value> {
fn initialization_options(&self) -> Option<serde_json::Value> {
None
}
}

View file

@ -1,6 +1,6 @@
name = "TypeScript"
path_suffixes = ["ts", "cts", "d.cts", "d.mts", "mts"]
line_comment = "// "
line_comments = ["// "]
autoclose_before = ";:.,=}])>"
brackets = [
{ start = "{", end = "}", close = true, newline = true },

View file

@ -8,7 +8,7 @@ pub struct UiuaLanguageServer;
#[async_trait]
impl LspAdapter for UiuaLanguageServer {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("uiua".into())
}

View file

@ -1,6 +1,6 @@
name = "Uiua"
path_suffixes = ["ua"]
line_comment = "# "
line_comments = ["# "]
autoclose_before = ")]}\""
brackets = [
{ start = "{", end = "}", close = true, newline = false},

View file

@ -40,7 +40,7 @@ impl VueLspAdapter {
}
#[async_trait]
impl super::LspAdapter for VueLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("vue-language-server".into())
}
@ -60,7 +60,7 @@ impl super::LspAdapter for VueLspAdapter {
ts_version: self.node.npm_package_latest_version("typescript").await?,
}) as Box<_>)
}
async fn initialization_options(&self) -> Option<Value> {
fn initialization_options(&self) -> Option<Value> {
let typescript_sdk_path = self.typescript_install_path.lock();
let typescript_sdk_path = typescript_sdk_path
.as_ref()

View file

@ -35,7 +35,7 @@ impl YamlLspAdapter {
#[async_trait]
impl LspAdapter for YamlLspAdapter {
async fn name(&self) -> LanguageServerName {
fn name(&self) -> LanguageServerName {
LanguageServerName("yaml-language-server".into())
}

View file

@ -1,6 +1,6 @@
name = "YAML"
path_suffixes = ["yml", "yaml"]
line_comment = "# "
line_comments = ["# "]
autoclose_before = ",]}"
brackets = [
{ start = "{", end = "}", close = true, newline = true },

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,230 @@
[
(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]*)*$")
)
(
(_
variable_type_function: (IDENTIFIER) @function
(FnCallArguments))
)
;; 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: "!" @keyword.exception
(
(IDENTIFIER) @variable.builtin
(#eq? @variable.builtin "_")
)
(PtrTypeStart "c" @variable.builtin)
(
(ContainerDeclType
[
(ErrorUnionExpr)
"enum"
]
)
(ContainerField (IDENTIFIER) @constant)
)
field_constant: (IDENTIFIER) @constant
(BUILTINIDENTIFIER) @keyword
((BUILTINIDENTIFIER) @keyword.import
(#any-of? @keyword.import "@import" "@cImport"))
(INTEGER) @number
(FLOAT) @number.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"
] @keyword
[
"for"
"while"
"break"
"continue"
] @keyword
[
"usingnamespace"
] @keyword.import
[
"try"
"catch"
] @keyword
[
"anytype"
(BuildinTypeExpr)
] @type.builtin
[
"const"
"var"
"volatile"
"allowzero"
"noalias"
] @type.qualifier
[
"addrspace"
"align"
"callconv"
"linksection"
] @keyword.storage
[
"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.begin
[
"("
")"
"["
"]"
"{"
"}"
] @indent.branch
[
(line_comment)
(container_doc_comment)
(doc_comment)
(LINESTRING)
] @indent.ignore

View file

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

View file

@ -543,7 +543,12 @@ fn init_panic_hook(app: &App, installation_id: Option<String>, session_id: Strin
let mut backtrace = backtrace
.frames()
.iter()
.filter_map(|frame| Some(format!("{:#}", frame.symbols().first()?.name()?)))
.flat_map(|frame| {
frame
.symbols()
.iter()
.filter_map(|frame| Some(format!("{:#}", frame.name()?)))
})
.collect::<Vec<_>>();
// Strip out leading stack frames for rust panic-handling.

View file

@ -143,7 +143,7 @@ pub fn initialize_workspace(app_state: Arc<AppState>, cx: &mut AppContext) {
cx.on_window_should_close(move |cx| {
handle
.update(cx, |workspace, cx| {
// We'll handle closing asynchoronously
// We'll handle closing asynchronously
workspace.close_window(&Default::default(), cx);
false
})
@ -370,16 +370,12 @@ fn initialize_pane(workspace: &mut Workspace, pane: &View<Pane>, cx: &mut ViewCo
}
fn about(_: &mut Workspace, _: &About, cx: &mut gpui::ViewContext<Workspace>) {
use std::fmt::Write as _;
let app_name = cx.global::<ReleaseChannel>().display_name();
let version = env!("CARGO_PKG_VERSION");
let mut message = format!("{app_name} {version}");
if let Some(sha) = cx.try_global::<AppCommitSha>() {
write!(&mut message, "\n\n{}", sha.0).unwrap();
}
let message = format!("{app_name} {version}");
let detail = cx.try_global::<AppCommitSha>().map(|sha| sha.0.as_ref());
let prompt = cx.prompt(PromptLevel::Info, &message, &["OK"]);
let prompt = cx.prompt(PromptLevel::Info, &message, detail, &["OK"]);
cx.foreground_executor()
.spawn(async {
prompt.await.ok();
@ -410,6 +406,7 @@ fn quit(_: &Quit, cx: &mut AppContext) {
cx.prompt(
PromptLevel::Info,
"Are you sure you want to quit?",
None,
&["Quit", "Cancel"],
)
})