zed/extensions/dart/src/dart.rs
Marshall Bowers c851e6edba
Add language_server_workspace_configuration to extension API (#10212)
This PR adds the ability for extensions to implement
`language_server_workspace_configuration` to provide workspace
configuration to the language server.

We've used the Dart extension as a motivating example for this, pulling
it out into an extension in the process.

Release Notes:

- Removed built-in support for Dart, in favor of making it available as
an extension. The Dart extension will be suggested for download when you
open a `.dart` file.

---------

Co-authored-by: Max <max@zed.dev>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
2024-04-05 17:04:07 -04:00

123 lines
4.3 KiB
Rust

use zed::lsp::CompletionKind;
use zed::settings::LspSettings;
use zed::{CodeLabel, CodeLabelSpan};
use zed_extension_api::{self as zed, serde_json, Result};
struct DartExtension;
impl zed::Extension for DartExtension {
fn new() -> Self {
Self
}
fn language_server_command(
&mut self,
_language_server_id: &zed::LanguageServerId,
worktree: &zed::Worktree,
) -> Result<zed::Command> {
let path = worktree
.which("dart")
.ok_or_else(|| "dart must be installed from dart.dev/get-dart".to_string())?;
Ok(zed::Command {
command: path,
args: vec!["language-server".to_string(), "--protocol=lsp".to_string()],
env: Default::default(),
})
}
fn language_server_workspace_configuration(
&mut self,
_language_server_id: &zed::LanguageServerId,
worktree: &zed::Worktree,
) -> Result<Option<serde_json::Value>> {
let settings = LspSettings::for_worktree("dart", worktree)
.ok()
.and_then(|lsp_settings| lsp_settings.settings.clone())
.unwrap_or_default();
Ok(Some(serde_json::json!({
"dart": settings
})))
}
fn label_for_completion(
&self,
_language_server_id: &zed::LanguageServerId,
completion: zed::lsp::Completion,
) -> Option<CodeLabel> {
let arrow = "";
match completion.kind? {
CompletionKind::Class => Some(CodeLabel {
filter_range: (0..completion.label.len()).into(),
spans: vec![CodeLabelSpan::literal(
completion.label,
Some("type".into()),
)],
code: String::new(),
}),
CompletionKind::Function | CompletionKind::Constructor | CompletionKind::Method => {
let mut parts = completion.detail.as_ref()?.split(arrow);
let (name, _) = completion.label.split_once('(')?;
let parameter_list = parts.next()?;
let return_type = parts.next()?;
let fn_name = " a";
let fat_arrow = " => ";
let call_expr = "();";
let code =
format!("{return_type}{fn_name}{parameter_list}{fat_arrow}{name}{call_expr}");
let parameter_list_start = return_type.len() + fn_name.len();
Some(CodeLabel {
spans: vec![
CodeLabelSpan::code_range(
code.len() - call_expr.len() - name.len()..code.len() - call_expr.len(),
),
CodeLabelSpan::code_range(
parameter_list_start..parameter_list_start + parameter_list.len(),
),
CodeLabelSpan::literal(arrow, None),
CodeLabelSpan::code_range(0..return_type.len()),
],
filter_range: (0..name.len()).into(),
code,
})
}
CompletionKind::Property => {
let class_start = "class A {";
let get = " get ";
let property_end = " => a; }";
let ty = completion.detail?;
let name = completion.label;
let code = format!("{class_start}{ty}{get}{name}{property_end}");
let name_start = class_start.len() + ty.len() + get.len();
Some(CodeLabel {
spans: vec![
CodeLabelSpan::code_range(name_start..name_start + name.len()),
CodeLabelSpan::literal(arrow, None),
CodeLabelSpan::code_range(class_start.len()..class_start.len() + ty.len()),
],
filter_range: (0..name.len()).into(),
code,
})
}
CompletionKind::Variable => {
let name = completion.label;
Some(CodeLabel {
filter_range: (0..name.len()).into(),
spans: vec![CodeLabelSpan::literal(name, Some("variable".into()))],
code: String::new(),
})
}
_ => None,
}
}
}
zed::register_extension!(DartExtension);