1use crate::diagnostics_scheduler::{
2 RustDiagnosticsSchedulerBoundaryV0, rust_diagnostics_scheduler_contract,
3};
4use crate::query_reuse::{RustQueryReuseBoundaryV0, rust_query_reuse_contract};
5use crate::workspace_runtime_registry::{
6 WorkspaceRuntimeRegistryBoundaryV0, workspace_runtime_registry_contract,
7};
8use crate::{
9 CANCEL_REQUEST_METHOD, CASCADE_AT_POSITION_REQUEST, NODE_TEXT_DOCUMENT_SYNC_KIND,
10 STYLE_CONTEXT_INDEX_REQUEST,
11};
12use omena_tsgo_client::{OmenaTsgoClientBoundarySummaryV0, summarize_omena_tsgo_client_boundary};
13use serde::Serialize;
14
15#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
16#[serde(rename_all = "camelCase")]
17pub struct OmenaLspServerBoundarySummaryV0 {
18 pub schema_version: &'static str,
19 pub product: &'static str,
20 pub server_name: &'static str,
21 pub migration_status: &'static str,
22 pub transport_contract: &'static str,
23 pub capabilities: OmenaLspServerCapabilitiesV0,
24 pub handler_surfaces: Vec<LspHandlerSurfaceV0>,
25 pub migration_phases: Vec<LspMigrationPhaseV0>,
26 pub blocking_work_policy: Vec<&'static str>,
27 pub tsgo_client_boundary: OmenaTsgoClientBoundarySummaryV0,
28 pub source_provider_adapter: SourceProviderDirectRustAdapterV0,
29 pub workspace_runtime_registry: WorkspaceRuntimeRegistryBoundaryV0,
30 pub diagnostics_scheduler: RustDiagnosticsSchedulerBoundaryV0,
31 pub query_reuse: RustQueryReuseBoundaryV0,
32 pub thin_client_endpoint: ThinClientEndpointV0,
33 pub multi_editor_distribution: MultiEditorDistributionV0,
34 pub node_parity_contracts: Vec<&'static str>,
35 pub next_decoupling_targets: Vec<&'static str>,
36}
37
38#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
39#[serde(rename_all = "camelCase")]
40pub struct OmenaLspServerCapabilitiesV0 {
41 pub text_document_sync: u8,
42 pub definition_provider: bool,
43 pub hover_provider: bool,
44 pub completion_provider: CompletionProviderCapabilityV0,
45 pub code_action_provider: CodeActionProviderCapabilityV0,
46 pub references_provider: bool,
47 pub code_lens_provider: ResolveProviderCapabilityV0,
48 pub rename_provider: RenameProviderCapabilityV0,
49 pub workspace: WorkspaceCapabilityV0,
50}
51
52#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
53#[serde(rename_all = "camelCase")]
54pub struct CompletionProviderCapabilityV0 {
55 pub trigger_characters: Vec<&'static str>,
56 pub resolve_provider: bool,
57}
58
59#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
60#[serde(rename_all = "camelCase")]
61pub struct CodeActionProviderCapabilityV0 {
62 pub code_action_kinds: Vec<&'static str>,
63 pub resolve_provider: bool,
64}
65
66#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
67#[serde(rename_all = "camelCase")]
68pub struct ResolveProviderCapabilityV0 {
69 pub resolve_provider: bool,
70}
71
72#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
73#[serde(rename_all = "camelCase")]
74pub struct RenameProviderCapabilityV0 {
75 pub prepare_provider: bool,
76}
77
78#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
79#[serde(rename_all = "camelCase")]
80pub struct WorkspaceCapabilityV0 {
81 pub workspace_folders: WorkspaceFoldersCapabilityV0,
82}
83
84#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
85#[serde(rename_all = "camelCase")]
86pub struct WorkspaceFoldersCapabilityV0 {
87 pub supported: bool,
88 pub change_notifications: bool,
89}
90
91#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
92#[serde(rename_all = "camelCase")]
93pub struct LspHandlerSurfaceV0 {
94 pub method: &'static str,
95 pub node_owner: &'static str,
96 pub rust_owner_target: &'static str,
97 pub migration_state: &'static str,
98}
99
100#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
101#[serde(rename_all = "camelCase")]
102pub struct LspMigrationPhaseV0 {
103 pub phase: &'static str,
104 pub goal: &'static str,
105 pub exit_gate: &'static str,
106}
107
108#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
109#[serde(rename_all = "camelCase")]
110pub struct ThinClientEndpointV0 {
111 pub product: &'static str,
112 pub endpoint_name: &'static str,
113 pub transport_contract: &'static str,
114 pub command_owner: &'static str,
115 pub standalone_package: &'static str,
116 pub split_repository: &'static str,
117 pub cargo_install_command: &'static str,
118 pub node_fallback_allowed: bool,
119 pub file_watcher_globs: Vec<&'static str>,
120 pub host_responsibilities: Vec<&'static str>,
121 pub rust_responsibilities: Vec<&'static str>,
122}
123
124#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
125#[serde(rename_all = "camelCase")]
126pub struct MultiEditorDistributionV0 {
127 pub product: &'static str,
128 pub owner: &'static str,
129 pub distribution_model: &'static str,
130 pub supported_editors: Vec<&'static str>,
131 pub install_surfaces: Vec<&'static str>,
132 pub documentation: Vec<&'static str>,
133 pub endpoint_policy: Vec<&'static str>,
134}
135
136#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
137#[serde(rename_all = "camelCase")]
138pub struct SourceProviderDirectRustAdapterV0 {
139 pub product: &'static str,
140 pub candidate_owner: &'static str,
141 pub style_definition_owner: &'static str,
142 pub type_fact_owner: &'static str,
143 pub request_path_policy: Vec<&'static str>,
144 pub provider_surfaces: Vec<&'static str>,
145}
146
147pub fn summarize_omena_lsp_server_boundary() -> OmenaLspServerBoundarySummaryV0 {
148 OmenaLspServerBoundarySummaryV0 {
149 schema_version: "0",
150 product: "omena-lsp-server.boundary",
151 server_name: "omena-css",
152 migration_status: "rustStable",
153 transport_contract: "LSP stdio or IPC JSON-RPC",
154 capabilities: current_node_lsp_capability_contract(),
155 handler_surfaces: lsp_handler_surfaces(),
156 migration_phases: lsp_migration_phases(),
157 blocking_work_policy: vec![
158 "noFullWorkspaceProgramOnRequestPath",
159 "queuedRequestCancellationBeforeProviderWork",
160 "tsgoProviderCancellationTokenBoundary",
161 "backgroundIndexAndTypeFactWarmup",
162 "staleOrUnresolvableFastReturn",
163 ],
164 tsgo_client_boundary: summarize_omena_tsgo_client_boundary(),
165 source_provider_adapter: source_provider_direct_rust_adapter_contract(),
166 workspace_runtime_registry: workspace_runtime_registry_contract(),
167 diagnostics_scheduler: rust_diagnostics_scheduler_contract(),
168 query_reuse: rust_query_reuse_contract(),
169 thin_client_endpoint: thin_client_endpoint_contract(),
170 multi_editor_distribution: multi_editor_distribution_contract(),
171 node_parity_contracts: vec![
172 "initializeCapabilities",
173 "textDocumentSync",
174 "workspaceFolders",
175 "dynamicFileWatchers",
176 "diagnosticsPush",
177 "codeLensRefresh",
178 ],
179 next_decoupling_targets: vec![],
180 }
181}
182
183pub fn source_provider_direct_rust_adapter_contract() -> SourceProviderDirectRustAdapterV0 {
184 SourceProviderDirectRustAdapterV0 {
185 product: "omena-lsp-server.source-provider-direct-rust-adapter",
186 candidate_owner: "omena-query/sourceSyntaxIndex",
187 style_definition_owner: "omena-query/styleHoverCandidates",
188 type_fact_owner: "omena-tsgo-client",
189 request_path_policy: vec![
190 "noNodeWorkspaceTypeResolverOnSourceProviderPath",
191 "buildQuerySourceSyntaxIndexOnDocumentChange",
192 "dedupeTargetAwareSourceCandidates",
193 "consumeQueryStyleHoverCandidates",
194 "consumeQuerySassModuleSources",
195 "consumeConfiguredPackageManifestPaths",
196 "consumeTsgoTypeFactsForTypedCxProjection",
197 "consumeSassPartialEvaluatorGeneratedSelectors",
198 "useOpenedDocumentIndexesBeforeWorkspaceFallback",
199 "unresolvedCandidatesRemainFastDiagnostics",
200 ],
201 provider_surfaces: vec![
202 "textDocument/hover",
203 "textDocument/definition",
204 "textDocument/references",
205 "textDocument/completion",
206 "textDocument/publishDiagnostics",
207 CASCADE_AT_POSITION_REQUEST,
208 STYLE_CONTEXT_INDEX_REQUEST,
209 ],
210 }
211}
212
213pub fn thin_client_endpoint_contract() -> ThinClientEndpointV0 {
214 ThinClientEndpointV0 {
215 product: "omena-lsp-server.thin-client-endpoint",
216 endpoint_name: "omena-css.thin-client-runtime-endpoint",
217 transport_contract: "LSP stdio JSON-RPC",
218 command_owner: "dist/bin/<platform>-<arch>/omena-lsp-server",
219 standalone_package: "omena-lsp-server",
220 split_repository: "https://github.com/omenien/omena-lsp-server",
221 cargo_install_command: "cargo install omena-lsp-server --version 0.1.5",
222 node_fallback_allowed: false,
223 file_watcher_globs: vec![
224 "**/*.module.{scss,css,less}",
225 "**/*.{ts,tsx,js,jsx,mts,cts,mjs,cjs,d.ts}",
226 "**/tsconfig*.json",
227 "**/jsconfig*.json",
228 "**/package.json",
229 "**/vite.config.{ts,mts,cts,js,mjs,cjs}",
230 "**/webpack.config.{ts,mts,cts,js,mjs,cjs}",
231 ],
232 host_responsibilities: vec![
233 "resolvePackagedRustBinary",
234 "resolveStandaloneRustCommand",
235 "buildThinClientServerOptions",
236 "declareStaticDocumentSelector",
237 "startLanguageClient",
238 "registerStaticFileWatchers",
239 "translateShowReferencesArguments",
240 "surfaceStartupErrors",
241 ],
242 rust_responsibilities: vec![
243 "ownLspLifecycle",
244 "ownWorkspaceState",
245 "ownDiagnosticsScheduling",
246 "ownProviderExecution",
247 "ownTsgoClientLifecycle",
248 ],
249 }
250}
251
252pub fn multi_editor_distribution_contract() -> MultiEditorDistributionV0 {
253 MultiEditorDistributionV0 {
254 product: "omena-lsp-server.multi-editor-distribution",
255 owner: "omena-lsp-server/distribution",
256 distribution_model: "standaloneRustLspServerWithThinEditorHosts",
257 supported_editors: vec!["vscode", "neovim", "zed"],
258 install_surfaces: vec![
259 "vsixBundledDistBinary",
260 "cargoInstallOmenaLspServer",
261 "repoLocalDistBin",
262 ],
263 documentation: vec![
264 "client/src/extension.ts",
265 "docs/clients/neovim.md",
266 "docs/clients/zed.md",
267 ],
268 endpoint_policy: vec![
269 "standaloneRustServerIsPrimaryMultiEditorEndpoint",
270 "nodeLspServerIsNotPrimaryEndpoint",
271 "editorClientsDoNotImplementProviderSemantics",
272 "editorsMayRunBesideNativeTypeScriptServer",
273 ],
274 }
275}
276
277pub fn current_node_lsp_capability_contract() -> OmenaLspServerCapabilitiesV0 {
278 OmenaLspServerCapabilitiesV0 {
279 text_document_sync: NODE_TEXT_DOCUMENT_SYNC_KIND,
280 definition_provider: true,
281 hover_provider: true,
282 completion_provider: CompletionProviderCapabilityV0 {
283 trigger_characters: vec!["'", "\"", "`", ",", ".", "$", "@", "-"],
284 resolve_provider: false,
285 },
286 code_action_provider: CodeActionProviderCapabilityV0 {
287 code_action_kinds: vec!["quickfix", "refactor.extract", "refactor.inline"],
288 resolve_provider: false,
289 },
290 references_provider: true,
291 code_lens_provider: ResolveProviderCapabilityV0 {
292 resolve_provider: false,
293 },
294 rename_provider: RenameProviderCapabilityV0 {
295 prepare_provider: true,
296 },
297 workspace: WorkspaceCapabilityV0 {
298 workspace_folders: WorkspaceFoldersCapabilityV0 {
299 supported: true,
300 change_notifications: true,
301 },
302 },
303 }
304}
305
306pub fn lsp_handler_surfaces() -> Vec<LspHandlerSurfaceV0> {
307 vec![
308 style_provider_handler("textDocument/definition"),
309 style_provider_handler("textDocument/hover"),
310 style_provider_handler("textDocument/completion"),
311 style_provider_handler("textDocument/codeAction"),
312 style_provider_handler("textDocument/references"),
313 style_provider_handler("textDocument/codeLens"),
314 style_provider_handler("textDocument/prepareRename"),
315 style_provider_handler("textDocument/rename"),
316 runtime_handler("initialized"),
317 runtime_handler("textDocument/didOpen"),
318 runtime_handler("textDocument/didChange"),
319 runtime_handler("textDocument/didClose"),
320 runtime_handler("workspace/didChangeWatchedFiles"),
321 runtime_handler("workspace/didChangeConfiguration"),
322 runtime_handler("workspace/didChangeWorkspaceFolders"),
323 diagnostics_handler("textDocument/publishDiagnostics"),
324 query_inspection_handler(CASCADE_AT_POSITION_REQUEST),
325 query_inspection_handler(STYLE_CONTEXT_INDEX_REQUEST),
326 runtime_handler(CANCEL_REQUEST_METHOD),
327 ]
328}
329
330fn style_provider_handler(method: &'static str) -> LspHandlerSurfaceV0 {
331 LspHandlerSurfaceV0 {
332 method,
333 node_owner: "server/lsp-server/src/providers",
334 rust_owner_target: "omena-lsp-server/providers/style-source",
335 migration_state: "providerParity",
336 }
337}
338
339fn runtime_handler(method: &'static str) -> LspHandlerSurfaceV0 {
340 LspHandlerSurfaceV0 {
341 method,
342 node_owner: "server/lsp-server/src/handler-registration.ts",
343 rust_owner_target: "omena-lsp-server/runtime",
344 migration_state: "implemented",
345 }
346}
347
348fn diagnostics_handler(method: &'static str) -> LspHandlerSurfaceV0 {
349 LspHandlerSurfaceV0 {
350 method,
351 node_owner: "server/lsp-server/src/diagnostics-scheduler.ts",
352 rust_owner_target: "omena-lsp-server/diagnostics",
353 migration_state: "implemented",
354 }
355}
356
357fn query_inspection_handler(method: &'static str) -> LspHandlerSurfaceV0 {
358 LspHandlerSurfaceV0 {
359 method,
360 node_owner: "server/lsp-server/src/query-inspection",
361 rust_owner_target: "omena-lsp-server/query-inspection",
362 migration_state: "implemented",
363 }
364}
365
366pub fn lsp_migration_phases() -> Vec<LspMigrationPhaseV0> {
367 vec![
368 LspMigrationPhaseV0 {
369 phase: "phase-0-boundary",
370 goal: "declare Rust LSP capability and handler parity with the Node server",
371 exit_gate: "rust/omena-lsp-server/boundary",
372 },
373 LspMigrationPhaseV0 {
374 phase: "phase-1-shell",
375 goal: "own initialize, shutdown, text sync, workspace folders, and watcher state in Rust",
376 exit_gate: "rust/omena-lsp-server/runtime-loop",
377 },
378 LspMigrationPhaseV0 {
379 phase: "phase-2-style-providers",
380 goal: "serve style-side hover, definition, references, diagnostics, and code lens from Rust",
381 exit_gate: "rust/omena-lsp-server/provider-parity",
382 },
383 LspMigrationPhaseV0 {
384 phase: "phase-3-source-providers",
385 goal: "replace Node WorkspaceTypeResolver hot path with a long-lived tsgo client and Rust query runtime",
386 exit_gate: "rust/omena-tsgo-client/boundary",
387 },
388 LspMigrationPhaseV0 {
389 phase: "phase-4-thin-client",
390 goal: "shrink the VS Code extension to UI commands and Rust LSP process orchestration",
391 exit_gate: "rust/omena-lsp-server/thin-client-boundary",
392 },
393 ]
394}