1use zed::lsp::CompletionKind;
2use zed::settings::LspSettings;
3use zed::{CodeLabel, CodeLabelSpan};
4use zed_extension_api::{self as zed, serde_json, Result};
5
6struct DartExtension;
7
8impl zed::Extension for DartExtension {
9 fn new() -> Self {
10 Self
11 }
12
13 fn language_server_command(
14 &mut self,
15 _language_server_id: &zed::LanguageServerId,
16 worktree: &zed::Worktree,
17 ) -> Result<zed::Command> {
18 let path = worktree
19 .which("dart")
20 .ok_or_else(|| "dart must be installed from dart.dev/get-dart".to_string())?;
21
22 Ok(zed::Command {
23 command: path,
24 args: vec!["language-server".to_string(), "--protocol=lsp".to_string()],
25 env: Default::default(),
26 })
27 }
28
29 fn language_server_workspace_configuration(
30 &mut self,
31 _language_server_id: &zed::LanguageServerId,
32 worktree: &zed::Worktree,
33 ) -> Result<Option<serde_json::Value>> {
34 let settings = LspSettings::for_worktree("dart", worktree)
35 .ok()
36 .and_then(|lsp_settings| lsp_settings.settings.clone())
37 .unwrap_or_default();
38
39 Ok(Some(serde_json::json!({
40 "dart": settings
41 })))
42 }
43
44 fn label_for_completion(
45 &self,
46 _language_server_id: &zed::LanguageServerId,
47 completion: zed::lsp::Completion,
48 ) -> Option<CodeLabel> {
49 let arrow = " → ";
50
51 match completion.kind? {
52 CompletionKind::Class => Some(CodeLabel {
53 filter_range: (0..completion.label.len()).into(),
54 spans: vec![CodeLabelSpan::literal(
55 completion.label,
56 Some("type".into()),
57 )],
58 code: String::new(),
59 }),
60 CompletionKind::Function | CompletionKind::Constructor | CompletionKind::Method => {
61 let mut parts = completion.detail.as_ref()?.split(arrow);
62 let (name, _) = completion.label.split_once('(')?;
63 let parameter_list = parts.next()?;
64 let return_type = parts.next()?;
65 let fn_name = " a";
66 let fat_arrow = " => ";
67 let call_expr = "();";
68
69 let code =
70 format!("{return_type}{fn_name}{parameter_list}{fat_arrow}{name}{call_expr}");
71
72 let parameter_list_start = return_type.len() + fn_name.len();
73
74 Some(CodeLabel {
75 spans: vec![
76 CodeLabelSpan::code_range(
77 code.len() - call_expr.len() - name.len()..code.len() - call_expr.len(),
78 ),
79 CodeLabelSpan::code_range(
80 parameter_list_start..parameter_list_start + parameter_list.len(),
81 ),
82 CodeLabelSpan::literal(arrow, None),
83 CodeLabelSpan::code_range(0..return_type.len()),
84 ],
85 filter_range: (0..name.len()).into(),
86 code,
87 })
88 }
89 CompletionKind::Property => {
90 let class_start = "class A {";
91 let get = " get ";
92 let property_end = " => a; }";
93 let ty = completion.detail?;
94 let name = completion.label;
95
96 let code = format!("{class_start}{ty}{get}{name}{property_end}");
97 let name_start = class_start.len() + ty.len() + get.len();
98
99 Some(CodeLabel {
100 spans: vec![
101 CodeLabelSpan::code_range(name_start..name_start + name.len()),
102 CodeLabelSpan::literal(arrow, None),
103 CodeLabelSpan::code_range(class_start.len()..class_start.len() + ty.len()),
104 ],
105 filter_range: (0..name.len()).into(),
106 code,
107 })
108 }
109 CompletionKind::Variable => {
110 let name = completion.label;
111
112 Some(CodeLabel {
113 filter_range: (0..name.len()).into(),
114 spans: vec![CodeLabelSpan::literal(name, Some("variable".into()))],
115 code: String::new(),
116 })
117 }
118 _ => None,
119 }
120 }
121}
122
123zed::register_extension!(DartExtension);