lib.rs

  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<String>;
  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}