Skip to main content

omena_lsp_server/
boundary.rs

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}