dart.rs

  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);