Skip to main content

eure_ls/
types.rs

1//! Core types for the Eure Language Server.
2//!
3//! This module contains types shared between native and WASM implementations.
4
5use std::collections::HashSet;
6
7#[cfg(not(target_arch = "wasm32"))]
8use eure::query::TextFileContent;
9use eure::query::{Glob, TextFile};
10use query_flow::RevisionCounter;
11use serde_json::Value;
12
13use crate::queries::{LspDiagnostics, LspFileDiagnostics, LspSemanticTokens};
14
15/// Platform-agnostic request ID.
16///
17/// LSP allows request IDs to be either integers or strings.
18#[derive(Clone, Debug, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)]
19#[serde(untagged)]
20pub enum CoreRequestId {
21    Int(i32),
22    Str(String),
23}
24
25impl CoreRequestId {
26    pub fn as_str(&self) -> String {
27        match self {
28            CoreRequestId::Int(n) => n.to_string(),
29            CoreRequestId::Str(s) => s.clone(),
30        }
31    }
32}
33
34impl From<i32> for CoreRequestId {
35    fn from(n: i32) -> Self {
36        CoreRequestId::Int(n)
37    }
38}
39
40impl From<String> for CoreRequestId {
41    fn from(s: String) -> Self {
42        CoreRequestId::Str(s)
43    }
44}
45
46impl From<&str> for CoreRequestId {
47    fn from(s: &str) -> Self {
48        CoreRequestId::Str(s.to_string())
49    }
50}
51
52impl From<&Value> for CoreRequestId {
53    fn from(v: &Value) -> Self {
54        serde_json::from_value(v.clone()).unwrap()
55    }
56}
57
58#[cfg(not(target_arch = "wasm32"))]
59impl From<lsp_server::RequestId> for CoreRequestId {
60    fn from(id: lsp_server::RequestId) -> Self {
61        serde_json::from_value(serde_json::to_value(&id).unwrap()).unwrap()
62    }
63}
64
65#[cfg(not(target_arch = "wasm32"))]
66impl From<&CoreRequestId> for lsp_server::RequestId {
67    fn from(id: &CoreRequestId) -> Self {
68        serde_json::from_value(serde_json::to_value(id).unwrap()).unwrap()
69    }
70}
71
72/// Effects the core needs the platform to perform.
73#[derive(Debug, Clone)]
74pub enum Effect {
75    /// Request to fetch a file's content.
76    FetchFile(TextFile),
77    /// Request to expand a glob pattern.
78    ExpandGlob {
79        /// Unique identifier for this glob request.
80        id: String,
81        /// The glob pattern to expand.
82        glob: Glob,
83    },
84}
85
86/// LSP error information.
87#[derive(Debug, Clone)]
88pub struct LspError {
89    pub code: i32,
90    pub message: String,
91}
92
93impl LspError {
94    pub fn new(code: i32, message: impl Into<String>) -> Self {
95        Self {
96            code,
97            message: message.into(),
98        }
99    }
100
101    pub fn internal_error(message: impl Into<String>) -> Self {
102        Self::new(-32603, message)
103    }
104
105    pub fn invalid_params(message: impl Into<String>) -> Self {
106        Self::new(-32602, message)
107    }
108
109    pub fn method_not_found(method: &str) -> Self {
110        Self::new(-32601, format!("Method not found: {}", method))
111    }
112}
113
114/// Output messages from the core.
115#[derive(Debug, Clone)]
116pub enum LspOutput {
117    /// Response to a request.
118    Response {
119        id: CoreRequestId,
120        result: Result<Value, LspError>,
121    },
122    /// Notification to send to client.
123    Notification { method: String, params: Value },
124}
125
126/// A completion request: document and cursor as a byte offset.
127///
128/// Not a query on purpose; see `eure::query::get_completions`.
129#[derive(Clone, Debug)]
130pub struct CompletionRequest {
131    pub file: TextFile,
132    pub offset: u32,
133}
134
135/// A hover request: document and cursor as a byte offset.
136///
137/// Not a query on purpose; see `eure::query::get_hover`.
138#[derive(Clone, Debug)]
139pub struct HoverRequest {
140    pub file: TextFile,
141    pub offset: u32,
142}
143
144/// Keep the UTF-16 position until the source is available, including unopened schemas.
145#[derive(Clone, Debug)]
146pub struct DefinitionRequest {
147    pub file: TextFile,
148    pub position: lsp_types::Position,
149}
150
151/// LSP commands. Each variant carries what is needed to (re-)execute the
152/// request once the assets it suspended on are available.
153#[derive(Clone)]
154pub enum CommandQuery {
155    SemanticTokensFull(LspSemanticTokens),
156    Completion(CompletionRequest),
157    Hover(HoverRequest),
158    Definition(DefinitionRequest),
159    SchemaContent(TextFile),
160}
161
162impl CommandQuery {
163    /// The document this command operates on.
164    pub fn file(&self) -> &TextFile {
165        match self {
166            CommandQuery::SemanticTokensFull(q) => &q.file,
167            CommandQuery::Completion(q) => &q.file,
168            CommandQuery::Hover(q) => &q.file,
169            CommandQuery::Definition(q) => &q.file,
170            CommandQuery::SchemaContent(file) => file,
171        }
172    }
173
174    /// Name used in log messages.
175    pub fn name(&self) -> &'static str {
176        match self {
177            CommandQuery::SemanticTokensFull(_) => "SemanticTokens",
178            CommandQuery::Completion(_) => "Completion",
179            CommandQuery::Hover(_) => "Hover",
180            CommandQuery::Definition(_) => "Definition",
181            CommandQuery::SchemaContent(_) => "SchemaContent",
182        }
183    }
184}
185
186/// Result of executing a command query.
187pub enum CommandResult {
188    SemanticTokens(Option<lsp_types::SemanticTokens>),
189    Completion(Vec<lsp_types::CompletionItem>),
190    Hover(Option<lsp_types::Hover>),
191    Definition(Vec<lsp_types::LocationLink>),
192    SchemaContent(String),
193}
194
195/// A pending LSP request waiting for assets to be resolved.
196pub struct PendingRequest {
197    /// The request ID.
198    pub id: CoreRequestId,
199    /// The command to execute.
200    pub command: CommandQuery,
201    /// Assets this request is waiting for.
202    pub waiting_for: HashSet<TextFile>,
203}
204
205/// Subscription for diagnostics with revision tracking (legacy per-URI).
206#[derive(Clone)]
207pub struct DiagnosticsSubscription {
208    pub query: LspDiagnostics,
209    pub last_revision: RevisionCounter,
210}
211
212/// Per-file diagnostics subscription with revision tracking.
213///
214/// Used for the new per-file polling approach where each file
215/// has its own subscription and revision counter.
216#[derive(Clone)]
217pub struct FileDiagnosticsSubscription {
218    pub file: TextFile,
219    pub query: LspFileDiagnostics,
220    pub last_revision: RevisionCounter,
221}
222
223// Native-only types for I/O operations
224
225/// Request to read a file from disk.
226#[cfg(not(target_arch = "wasm32"))]
227pub struct IoRequest {
228    pub file: TextFile,
229}
230
231/// Response from reading a file.
232#[cfg(not(target_arch = "wasm32"))]
233pub struct IoResponse {
234    pub file: TextFile,
235    /// Content or error from fetching the file.
236    pub result: Result<TextFileContent, anyhow::Error>,
237}