Skip to repository content209 lines · 7.1 KB · rust
tenant.openagents/omega
No repository description is available.
OpenAgents Git authority 2026-07-28T02:55:45.954Z Public web read
NIP-34 coordinate
30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omegaMaintainersHidden in public view
References2 branches · 1 tag
Read-only clone
git clone https://openagents.com/git/tenant.openagents/omega.gitBrowse files
test_extension.rs
1use std::fs;
2use zed::lsp::CompletionKind;
3use zed::{CodeLabel, CodeLabelSpan, LanguageServerId};
4use zed_extension_api::process::Command;
5use zed_extension_api::{self as zed, Result};
6
7struct TestExtension {
8 cached_binary_path: Option<String>,
9}
10
11impl TestExtension {
12 fn language_server_binary_path(
13 &mut self,
14 language_server_id: &LanguageServerId,
15 _worktree: &zed::Worktree,
16 ) -> Result<String> {
17 let (platform, arch) = zed::current_platform();
18
19 let current_dir = std::env::current_dir().unwrap();
20 println!("current_dir: {}", current_dir.display());
21 assert_eq!(
22 current_dir.file_name().unwrap().to_str().unwrap(),
23 "test-extension"
24 );
25
26 fs::create_dir_all(current_dir.join("dir-created-with-abs-path")).unwrap();
27 fs::create_dir_all("./dir-created-with-rel-path").unwrap();
28 fs::write("file-created-with-rel-path", b"contents 1").unwrap();
29 fs::write(
30 current_dir.join("file-created-with-abs-path"),
31 b"contents 2",
32 )
33 .unwrap();
34 assert_eq!(
35 fs::read("file-created-with-rel-path").unwrap(),
36 b"contents 1"
37 );
38 assert_eq!(
39 fs::read("file-created-with-abs-path").unwrap(),
40 b"contents 2"
41 );
42
43 let command = match platform {
44 zed::Os::Linux | zed::Os::Mac => Command::new("echo"),
45 zed::Os::Windows => Command::new("cmd").args(["/C", "echo"]),
46 };
47 let output = command.arg("hello from a child process!").output()?;
48 println!(
49 "command output: {}",
50 String::from_utf8_lossy(&output.stdout).trim()
51 );
52
53 if let Some(path) = &self.cached_binary_path
54 && fs::metadata(path).is_ok_and(|stat| stat.is_file())
55 {
56 return Ok(path.clone());
57 }
58
59 zed::set_language_server_installation_status(
60 language_server_id,
61 &zed::LanguageServerInstallationStatus::CheckingForUpdate,
62 );
63 let release = zed::latest_github_release(
64 "gleam-lang/gleam",
65 zed::GithubReleaseOptions {
66 require_assets: true,
67 pre_release: false,
68 },
69 )?;
70
71 let ext = "tar.gz";
72 let download_type = zed::DownloadedFileType::GzipTar;
73
74 // Do this if you want to actually run this extension -
75 // the actual asset is a .zip. But the integration test is simpler
76 // if every platform uses .tar.gz.
77 //
78 // ext = "zip";
79 // download_type = zed::DownloadedFileType::Zip;
80
81 let asset_name = format!(
82 "gleam-{version}-{arch}-{os}.{ext}",
83 version = release.version,
84 arch = match arch {
85 zed::Architecture::Aarch64 => "aarch64",
86 zed::Architecture::X8664 => "x86_64",
87 },
88 os = match platform {
89 zed::Os::Mac => "apple-darwin",
90 zed::Os::Linux => "unknown-linux-musl",
91 zed::Os::Windows => "pc-windows-msvc",
92 },
93 );
94
95 let asset = release
96 .assets
97 .iter()
98 .find(|asset| asset.name == asset_name)
99 .ok_or_else(|| format!("no asset found matching {:?}", asset_name))?;
100
101 let version_dir = format!("gleam-{}", release.version);
102 let binary_path = format!("{version_dir}/gleam");
103
104 if !fs::metadata(&binary_path).is_ok_and(|stat| stat.is_file()) {
105 zed::set_language_server_installation_status(
106 language_server_id,
107 &zed::LanguageServerInstallationStatus::Downloading,
108 );
109
110 zed::download_file(&asset.download_url, &version_dir, download_type)
111 .map_err(|e| format!("failed to download file: {e}"))?;
112
113 zed::set_language_server_installation_status(
114 language_server_id,
115 &zed::LanguageServerInstallationStatus::None,
116 );
117
118 let entries =
119 fs::read_dir(".").map_err(|e| format!("failed to list working directory {e}"))?;
120 for entry in entries {
121 let entry = entry.map_err(|e| format!("failed to load directory entry {e}"))?;
122 let filename = entry.file_name();
123 let filename = filename.to_str().unwrap();
124 if filename.starts_with("gleam-") && filename != version_dir {
125 fs::remove_dir_all(entry.path()).ok();
126 }
127 }
128 }
129
130 self.cached_binary_path = Some(binary_path.clone());
131 Ok(binary_path)
132 }
133}
134
135impl zed::Extension for TestExtension {
136 fn new() -> Self {
137 Self {
138 cached_binary_path: None,
139 }
140 }
141
142 fn language_server_command(
143 &mut self,
144 language_server_id: &LanguageServerId,
145 worktree: &zed::Worktree,
146 ) -> Result<zed::Command> {
147 Ok(zed::Command {
148 command: self.language_server_binary_path(language_server_id, worktree)?,
149 args: vec!["lsp".to_string()],
150 env: Default::default(),
151 })
152 }
153
154 fn label_for_completion(
155 &self,
156 _language_server_id: &LanguageServerId,
157 completion: zed::lsp::Completion,
158 ) -> Option<zed::CodeLabel> {
159 let name = &completion.label;
160 let ty = strip_newlines_from_detail(&completion.detail?);
161 let let_binding = "let a";
162 let colon = ": ";
163 let assignment = " = ";
164 let call = match completion.kind? {
165 CompletionKind::Function | CompletionKind::Constructor => "()",
166 _ => "",
167 };
168 let code = format!("{let_binding}{colon}{ty}{assignment}{name}{call}");
169
170 Some(CodeLabel {
171 spans: vec![
172 CodeLabelSpan::code_range({
173 let start = let_binding.len() + colon.len() + ty.len() + assignment.len();
174 start..start + name.len()
175 }),
176 CodeLabelSpan::code_range({
177 let start = let_binding.len();
178 start..start + colon.len()
179 }),
180 CodeLabelSpan::code_range({
181 let start = let_binding.len() + colon.len();
182 start..start + ty.len()
183 }),
184 ],
185 filter_range: (0..name.len()).into(),
186 code,
187 })
188 }
189}
190
191zed::register_extension!(TestExtension);
192
193/// Removes newlines from the completion detail.
194///
195/// The Gleam LSP can return types containing newlines, which causes formatting
196/// issues within the Zed completions menu.
197fn strip_newlines_from_detail(detail: &str) -> String {
198 let without_newlines = detail
199 .replace("->\n ", "-> ")
200 .replace("\n ", "")
201 .replace(",\n", "");
202
203 let comma_delimited_parts = without_newlines.split(',');
204 comma_delimited_parts
205 .map(|part| part.trim())
206 .collect::<Vec<_>>()
207 .join(", ")
208}
209