1use plugin::prelude::*;
2use serde::Deserialize;
3use serde_json::json;
4use std::fs;
5use std::path::PathBuf;
6
7#[import]
8fn command(string: &str) -> Option<Vec<u8>>;
9
10// #[no_mangle]
11// // TODO: switch len from usize to u32?
12// pub extern "C" fn #outer_fn_name(ptr: *const u8, len: usize) -> *const ::plugin::__Buffer {
13// // setup
14// let buffer = ::plugin::__Buffer { ptr, len };
15// let data = unsafe { buffer.to_vec() };
16
17// // operation
18// let data: #ty = match ::plugin::bincode::deserialize(&data) {
19// Ok(d) => d,
20// Err(e) => panic!("Data passed to function not deserializable."),
21// };
22// let result = #inner_fn_name(#args);
23// let new_data: Result<Vec<u8>, _> = ::plugin::bincode::serialize(&result);
24// let new_data = new_data.unwrap();
25
26// // teardown
27// let new_buffer = unsafe { ::plugin::__Buffer::from_vec(new_data) };
28// return new_buffer.leak_to_heap();
29// }
30
31// extern "C" {
32// fn __command(buffer: u64) -> u64;
33// }
34
35// #[no_mangle]
36// fn command(string: &str) -> Option<Vec<u8>> {
37// dbg!("executing command: {}", string);
38// // setup
39// let data = string;
40// let data = ::plugin::bincode::serialize(&data).unwrap();
41// let buffer = unsafe { ::plugin::__Buffer::from_vec(data) };
42
43// // operation
44// let new_buffer = unsafe { __command(buffer.into_u64()) };
45// let new_data = unsafe { ::plugin::__Buffer::from_u64(new_buffer).to_vec() };
46// let new_data: Option<Vec<u8>> = match ::plugin::bincode::deserialize(&new_data) {
47// Ok(d) => d,
48// Err(e) => panic!("Data returned from function not deserializable."),
49// };
50
51// // teardown
52// return new_data;
53// }
54
55// TODO: some sort of macro to generate ABI bindings
56// extern "C" {
57// pub fn hello(item: u32) -> u32;
58// pub fn bye(item: u32) -> u32;
59// }
60
61// #[bind]
62// pub async fn name(u32) -> u32 {
63
64// }
65
66// #[no_mangle]
67// pub extern "C" fn very_unique_name_of_course() -> impl std::future::Future<Output = u32> {
68// async move {
69// std::fs::read_to_string("heck.txt").unwrap().len() as u32
70// }
71// }
72
73const BIN_PATH: &'static str =
74 "node_modules/vscode-json-languageserver/bin/vscode-json-languageserver";
75
76#[export]
77pub fn name() -> &'static str {
78 // let number = unsafe { hello(27) };
79 // let number = unsafe { bye(28) };
80 // println!("got: {}", number);
81 "vscode-json-languageserver"
82}
83
84#[export]
85pub fn server_args() -> Vec<String> {
86 vec!["--stdio".into()]
87}
88
89#[export]
90pub fn fetch_latest_server_version() -> Option<String> {
91 #[derive(Deserialize)]
92 struct NpmInfo {
93 versions: Vec<String>,
94 }
95
96 // TODO: command returns error code
97 let output =
98 command("npm info vscode-json-languageserver --json").expect("could not run command");
99 // if !output.is_ok() {
100 // return None;
101 // }
102
103 let output = String::from_utf8(output).unwrap();
104 dbg!(&output);
105
106 let mut info: NpmInfo = serde_json::from_str(&output).ok()?;
107 info.versions.pop()
108}
109
110#[export]
111pub fn fetch_server_binary(container_dir: PathBuf, version: String) -> Result<PathBuf, String> {
112 let version_dir = container_dir.join(version.as_str());
113 fs::create_dir_all(&version_dir)
114 .map_err(|_| "failed to create version directory".to_string())?;
115 let binary_path = version_dir.join(BIN_PATH);
116
117 if fs::metadata(&binary_path).is_err() {
118 let output = command(&format!(
119 "npm install vscode-json-languageserver@{}",
120 version
121 ));
122 let output = output.map(String::from_utf8);
123 dbg!(&output);
124 if output.is_none() {
125 return Err("failed to install vscode-json-languageserver".to_string());
126 }
127
128 if let Some(mut entries) = fs::read_dir(&container_dir).ok() {
129 while let Some(entry) = entries.next() {
130 if let Some(entry) = entry.ok() {
131 let entry_path = entry.path();
132 if entry_path.as_path() != version_dir {
133 fs::remove_dir_all(&entry_path).ok();
134 }
135 }
136 }
137 }
138 }
139
140 Ok(binary_path)
141}
142
143#[export]
144pub fn cached_server_binary(container_dir: PathBuf) -> Option<PathBuf> {
145 let mut last_version_dir = None;
146 println!("reading directory");
147 let mut entries = fs::read_dir(&container_dir).ok()?;
148
149 while let Some(entry) = entries.next() {
150 println!("looking at entries");
151 let entry = entry.ok()?;
152 println!("some more stuff");
153 if entry.file_type().ok()?.is_dir() {
154 println!("this is it!");
155
156 last_version_dir = Some(entry.path());
157 }
158 }
159
160 let last_version_dir = last_version_dir?;
161 println!("here we go");
162 let bin_path = last_version_dir.join(BIN_PATH);
163 if bin_path.exists() {
164 dbg!(&bin_path);
165 Some(bin_path)
166 } else {
167 println!("no binary found");
168 None
169 }
170}
171
172#[export]
173pub fn label_for_completion(label: String) -> Option<String> {
174 None
175}
176
177#[export]
178pub fn initialization_options() -> Option<String> {
179 Some("{ \"provideFormatter\": true }".to_string())
180}
181
182#[export]
183pub fn id_for_language(name: String) -> Option<String> {
184 if name == "JSON" {
185 Some("jsonc".into())
186 } else {
187 None
188 }
189}