1use zed::lsp::{Symbol, SymbolKind};
2use zed::{CodeLabel, CodeLabelSpan};
3use zed_extension_api::{self as zed, Result};
4
5struct HaskellExtension;
6
7impl zed::Extension for HaskellExtension {
8 fn new() -> Self {
9 Self
10 }
11
12 fn language_server_command(
13 &mut self,
14 _language_server_id: &zed::LanguageServerId,
15 worktree: &zed::Worktree,
16 ) -> Result<zed::Command> {
17 let path = worktree
18 .which("haskell-language-server-wrapper")
19 .ok_or_else(|| "hls must be installed via ghcup".to_string())?;
20
21 Ok(zed::Command {
22 command: path,
23 args: vec!["lsp".to_string()],
24 env: worktree.shell_env(),
25 })
26 }
27
28 fn label_for_symbol(
29 &self,
30 _language_server_id: &zed::LanguageServerId,
31 symbol: Symbol,
32 ) -> Option<CodeLabel> {
33 let name = &symbol.name;
34
35 let (code, display_range, filter_range) = match symbol.kind {
36 SymbolKind::Struct => {
37 let data_decl = "data ";
38 let code = format!("{data_decl}{name} = A");
39 let display_range = 0..data_decl.len() + name.len();
40 let filter_range = data_decl.len()..display_range.end;
41 (code, display_range, filter_range)
42 }
43 SymbolKind::Constructor => {
44 let data_decl = "data A = ";
45 let code = format!("{data_decl}{name}");
46 let display_range = data_decl.len()..data_decl.len() + name.len();
47 let filter_range = 0..name.len();
48 (code, display_range, filter_range)
49 }
50 SymbolKind::Variable => {
51 let code = format!("{name} :: T");
52 let display_range = 0..name.len();
53 let filter_range = 0..name.len();
54 (code, display_range, filter_range)
55 }
56 _ => return None,
57 };
58
59 Some(CodeLabel {
60 spans: vec![CodeLabelSpan::code_range(display_range)],
61 filter_range: filter_range.into(),
62 code,
63 })
64 }
65}
66
67zed::register_extension!(HaskellExtension);