1use crate::types::{CompletionItem, Diagnostic, FoldingRange, Hover, InitializeParams, LocationRange, StructureItem, WorkspaceEdit, WorkspaceSymbol};
2use core::range::Range;
3use oak_core::{language::Language, source::Source, tree::RedNode};
4use oak_vfs::{Vfs, WritableVfs};
5use std::future::Future;
6
7pub trait LanguageService: Send + Sync {
8 type Lang: Language;
9 type Vfs: WritableVfs;
10
11 fn vfs(&self) -> &Self::Vfs;
13
14 fn workspace(&self) -> &crate::workspace::WorkspaceManager;
16
17 fn get_source(&self, uri: &str) -> Option<Box<dyn Source + Send + Sync>> {
19 self.vfs().get_source(uri).map(|s| Box::new(s) as Box<dyn Source + Send + Sync>)
20 }
21
22 fn get_root(&self, _uri: &str) -> impl Future<Output = Option<RedNode<'_, Self::Lang>>> + Send + '_ {
25 async { None }
26 }
27
28 fn with_root<'a, R, F>(&'a self, uri: &'a str, f: F) -> impl Future<Output = Option<R>> + Send + 'a
30 where
31 R: Send,
32 F: FnOnce(RedNode<'a, Self::Lang>) -> R + Send + 'a,
33 {
34 async move {
35 let root = self.get_root(uri).await?;
36 Some(f(root))
37 }
38 }
39
40 fn with_roots<'a, R, F>(&'a self, uris: Vec<String>, f: F) -> impl Future<Output = Vec<R>> + Send + 'a
42 where
43 R: Send + 'static,
44 F: Fn(RedNode<'a, Self::Lang>) -> R + Send + Sync + 'a,
45 {
46 let mut futures = Vec::new();
47 let f = std::sync::Arc::new(f);
48
49 for uri in uris {
50 let f = f.clone();
51 futures.push(async move { if let Some(root) = self.get_root(&uri).await { Some(f(root)) } else { None } });
52 }
53
54 async move { futures::future::join_all(futures).await.into_iter().flatten().collect() }
55 }
56
57 fn hover(&self, _uri: &str, _range: Range<usize>) -> impl Future<Output = Option<Hover>> + Send + '_ {
59 async { None }
60 }
61
62 fn folding_ranges(&self, _uri: &str) -> impl Future<Output = Vec<FoldingRange>> + Send + '_ {
64 async { vec![] }
65 }
66
67 fn document_symbols(&self, _uri: &str) -> impl Future<Output = Vec<StructureItem>> + Send + '_ {
69 async { vec![] }
70 }
71
72 fn workspace_symbols(&self, _query: &str) -> impl Future<Output = Vec<WorkspaceSymbol>> + Send + '_ {
74 async { vec![] }
75 }
76
77 fn list_all_files(&self, root_uri: &str) -> impl Future<Output = Vec<String>> + Send + '_ {
79 let root_uri = root_uri.to_string();
80 async move {
81 let mut files = Vec::new();
82 let mut stack = vec![root_uri];
83
84 while let Some(uri) = stack.pop() {
85 if self.vfs().is_file(&uri) {
86 files.push(uri);
87 }
88 else if self.vfs().is_dir(&uri) {
89 if let Some(entries) = self.vfs().read_dir(&uri) {
90 for entry in entries {
91 stack.push(entry);
92 }
93 }
94 }
95 }
96 files
97 }
98 }
99
100 fn definition<'a>(&'a self, _uri: &'a str, _range: Range<usize>) -> impl Future<Output = Vec<LocationRange>> + Send + 'a {
102 async { vec![] }
103 }
104
105 fn references<'a>(&'a self, _uri: &'a str, _range: Range<usize>) -> impl Future<Output = Vec<LocationRange>> + Send + 'a {
107 async { vec![] }
108 }
109
110 fn rename<'a>(&'a self, _uri: &'a str, _range: Range<usize>, _new_name: String) -> impl Future<Output = Option<WorkspaceEdit>> + Send + 'a {
112 async { None }
113 }
114
115 fn completion<'a>(&'a self, _uri: &'a str, _position: usize) -> impl Future<Output = Vec<CompletionItem>> + Send + 'a {
117 async { vec![] }
118 }
119
120 fn diagnostics<'a>(&'a self, _uri: &'a str) -> impl Future<Output = Vec<Diagnostic>> + Send + 'a {
122 async { vec![] }
123 }
124
125 fn initialize<'a>(&'a self, _params: InitializeParams) -> impl Future<Output = ()> + Send + 'a {
127 async {}
128 }
129
130 fn initialized<'a>(&'a self) -> impl Future<Output = ()> + Send + 'a {
132 async {}
133 }
134
135 fn shutdown<'a>(&'a self) -> impl Future<Output = ()> + Send + 'a {
137 async {}
138 }
139
140 fn did_save<'a>(&'a self, _uri: &'a str) -> impl Future<Output = ()> + Send + 'a {
142 async {}
143 }
144
145 fn did_close<'a>(&'a self, _uri: &'a str) -> impl Future<Output = ()> + Send + 'a {
147 async {}
148 }
149}
150
151pub trait LanguageServiceExt: LanguageService {
153 #[cfg(feature = "axum")]
155 fn into_axum_router(self) -> axum::Router
156 where
157 Self: Sized + 'static,
158 {
159 crate::server::axum_router(std::sync::Arc::new(self))
160 }
161}
162
163impl<T: LanguageService> LanguageServiceExt for T {}